React.jsで入力値を正しく検証する方法
-
21-12-2019 - |
質問
私は簡単な形をしています。すべてのコンポーネントと状態はページコンポーネントに保持されています。2つのディスプレイヘッダーと3つの入力フィールドがあります。最初の入力はテキストであると想定されており、2番目と3番目はintsであると想定されています。ユーザーが間違った種類のデータを入力すると、入力フィールドの横にエラーメッセージが表示されます。私の質問はReact.js
のベストプラクティスに関連しています価値が有効であると判断した人は?入力フィールドの唯一のジョブが状態を状態を保持するコンポーネントに戻すことであることになると、これは値が有効かどうかを判断できることを意味します。
どのように私はポップアップが表示されますか?Adaptive_Inputに渡される新しいBoolean State要素をトリガする必要がある場合は、Adaptive_Inputを実行してエラーメッセージを表示する必要がありますか?
js:
/**
* @jsx React.DOM
*/
var Adaptive_Input = React.createClass({
handle_change: function(){
var new_text = this.refs.input.getDOMNode().value;
this.props.on_Input_Change(new_text);
},
render: function(){
return (
<div className='adaptive_placeholder_input_container'>
<input
className="adaptive_input"
type="text"
required="required"
onChange= {this.handle_change}
ref="input"
></input>
<label
className="adaptive_placeholder"
alt={this.props.initial}
placeholder={this.props.focused}
></label>
</div>
);
}
});
var Form = React.createClass({
render: function(){
return (
<form>
<Adaptive_Input
initial={'Name Input'}
focused={'Name Input'}
on_Input_Change={this.props.handle_text_input}
/>
<Adaptive_Input
initial={'Value 1'}
focused={'Value 1'}
on_Input_Change={this.props.handle_value_1_input}
/>
<Adaptive_Input
initial={'Value 2'}
focused={'Value 2'}
on_Input_Change={this.props.handle_value_2_input}
/>
</form>
);
}
});
var Page = React.createClass({
getInitialState: function(){
return {
Name : "No Name",
Value_1 : '0',
Value_2 : '0',
Display_Value: '0'
};
},
handle_text_input: function(new_text){
this.setState({
Name: new_text
});
},
handle_value_1_input: function(new_value){
console.log("===");
var updated_display = parseInt(new_value) + parseInt(this.state.Value_2);
updated_display = updated_display.toString();
this.setState({
Display_Value: updated_display
});
},
handle_value_2_input: function(new_value){
var updated_display = parseInt(this.state.Value_1) + parseInt(new_value);
updated_display = updated_display.toString();
this.setState({
Display_Value: updated_display
});
},
render: function(){
return(
<div>
<h2>{this.state.Name}</h2>
<h2>Value 1 + Value 2 = {this.state.Display_Value}</h2>
<Form
handle_text_input={this.handle_text_input}
handle_value_1_input = {this.handle_value_1_input}
handle_value_2_input = {this.handle_value_2_input}
/>
</div>
);
}
});
React.renderComponent(<Page />, document.body);
. 解決
最初に、ここに言及したことの一例です。 http://jsbin.com/rixido/2/ed
React.jsで入力値を正しく検証する方法?
あなたが望む。 REATはデータモデルをレンダリングするためのものです。データモデルは何が有効かどうかを知っておくべきです。バックボーンモデル、JSONデータ、またはデータを表現したいものとエラー状態のものを使用できます。
より具体的には:
Reactは一般にあなたのデータに対して不織布です。レンダリングとイベントへの対応のためのものです。
以下の規則は次のとおりです。
- 要素はそれらの状態を変えることができます。
- 彼らは小道具を変えることができません。
- 彼らはトップレベルの小道具を変更するコールバックを呼び出すことができます。
何かが小道具や州であるべきかどうかを決定する方法これを考慮してください:テキストフィールド以外のアプリの一部は、入力された値が悪いことを知りたいですか?いいえの場合は状態にしてください。もしそうなら、それはPROPであるべきです。
たとえば、「このページで2つのエラーがある」というレンダリングに別のビューを希望されている場合は、それからあなたのエラーはトップベルデータモデルに知らなければならないでしょう。
それはどこに住んでいるべきですか?
アプリがバックボーンモデルを(たとえば)レンダリングしていた場合、モデル自体にはValidate()メソッドとValidateErrorプロパティがあります。他のスマートオブジェクトを同じようにレンダリングすることができます。 REATはまた、小道具を最小限に保ち、残りのデータを生成しようとしているとも言います。それで、あなたがバリデータを持っていたならば(例えば https://github.com/flatiron/revalidator )それからあなたの検証は細流化されそしてどれかコンポーネントは、それが有効かどうかを確認するためにそれが一致する検証で小道具をチェックすることができます。
それはほとんどあなた次第です。
(< PESFORY は、バックボーンモデルを使用して と反応させてレンダリングします。私は誤りを記述し、エラーがあるかどうかを示すトップベルエラーアラートがあります。)
他のヒント
npm install --save redux-form
IM Eメールを検証してフォームを検証する単純な電子メールと送信ボタンフォームを書き込みます。redux-formを使用すると、既定ではFORMがhtml onsubmitアクションでevent.preventDefault()を実行します。
import React, {Component} from 'react';
import {reduxForm} from 'redux-form';
class LoginForm extends Component {
onSubmit(props) {
//do your submit stuff
}
render() {
const {fields: {email}, handleSubmit} = this.props;
return (
<form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<input type="text" placeholder="Email"
className={`form-control ${email.touched && email.invalid ? 'has-error' : '' }`}
{...email}
/>
<span className="text-help">
{email.touched ? email.error : ''}
</span>
<input type="submit"/>
</form>
);
}
}
function validation(values) {
const errors = {};
const emailPattern = /(.+)@(.+){2,}\.(.+){2,}/;
if (!emailPattern.test(values.email)) {
errors.email = 'Enter a valid email';
}
return errors;
}
LoginForm = reduxForm({
form: 'LoginForm',
fields: ['email'],
validate: validation
}, null, null)(LoginForm);
export default LoginForm;
. このライブラリあなたはフォーム要素のコンポーネントを包み、letします。バリデータをフォーマットで定義します。 -
<Validation group="myGroup1"
validators={[
{
validator: (val) => !validator.isEmpty(val),
errorMessage: "Cannot be left empty"
},...
}]}>
<TextField value={this.state.value}
className={styles.inputStyles}
onChange={
(evt)=>{
console.log("you have typed: ", evt.target.value);
}
}/>
</Validation>
. あなたのJSフィイドルはもう機能しません。 私はそれを修正しました: http://jsfiddle.net/tkrotoff/bgc6e/40/< React 16とES6クラスを使用しています。
class Adaptive_Input extends React.Component {
handle_change(e) {
var new_text = e.currentTarget.value;
this.props.on_Input_Change(new_text);
}
render() {
return (
<div className="adaptive_placeholder_input_container">
<input
className="adaptive_input"
type="text"
required="required"
onChange={this.handle_change.bind(this)} />
<label
className="adaptive_placeholder"
alt={this.props.initial}
placeholder={this.props.focused} />
</div>
);
}
}
class Form extends React.Component {
render() {
return (
<form>
<Adaptive_Input
initial={'Name Input'}
focused={'Name Input'}
on_Input_Change={this.props.handle_text_input} />
<Adaptive_Input
initial={'Value 1'}
focused={'Value 1'}
on_Input_Change={this.props.handle_value_1_input} />
<Adaptive_Input
initial={'Value 2'}
focused={'Value 2'}
on_Input_Change={this.props.handle_value_2_input} />
</form>
);
}
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {
Name: 'No Name',
Value_1: '0',
Value_2: '0',
Display_Value: '0'
};
}
handle_text_input(new_text) {
this.setState({
Name: new_text
});
}
handle_value_1_input(new_value) {
new_value = parseInt(new_value);
var updated_display = new_value + parseInt(this.state.Value_2);
updated_display = updated_display.toString();
this.setState({
Value_1: new_value,
Display_Value: updated_display
});
}
handle_value_2_input(new_value) {
new_value = parseInt(new_value);
var updated_display = parseInt(this.state.Value_1) + new_value;
updated_display = updated_display.toString();
this.setState({
Value_2: new_value,
Display_Value: updated_display
});
}
render() {
return(
<div>
<h2>{this.state.Name}</h2>
<h2>Value 1 + Value 2 = {this.state.Display_Value}</h2>
<Form
handle_text_input={this.handle_text_input.bind(this)}
handle_value_1_input={this.handle_value_1_input.bind(this)}
handle_value_2_input={this.handle_value_2_input.bind(this)}
/>
</div>
);
}
}
ReactDOM.render(<Page />, document.getElementById('app'));
.
このライブラリのおかげでフォームの検証でハッキングされました。 https:/ /github.com/tkrotoff/React-form-with-constraints => http://jsfiddle.net/tkrotoff/k4qa4heg/
href="https://i.stack.imgur.com/axfrs.png" rel="nofollownoreferrer">
const { FormWithConstraints, FieldFeedbacks, FieldFeedback } = ReactFormWithConstraints;
class Adaptive_Input extends React.Component {
static contextTypes = {
form: PropTypes.object.isRequired
};
constructor(props) {
super(props);
this.state = {
field: undefined
};
this.fieldWillValidate = this.fieldWillValidate.bind(this);
this.fieldDidValidate = this.fieldDidValidate.bind(this);
}
componentWillMount() {
this.context.form.addFieldWillValidateEventListener(this.fieldWillValidate);
this.context.form.addFieldDidValidateEventListener(this.fieldDidValidate);
}
componentWillUnmount() {
this.context.form.removeFieldWillValidateEventListener(this.fieldWillValidate);
this.context.form.removeFieldDidValidateEventListener(this.fieldDidValidate);
}
fieldWillValidate(fieldName) {
if (fieldName === this.props.name) this.setState({field: undefined});
}
fieldDidValidate(field) {
if (field.name === this.props.name) this.setState({field});
}
handle_change(e) {
var new_text = e.currentTarget.value;
this.props.on_Input_Change(e, new_text);
}
render() {
const { field } = this.state;
let className = 'adaptive_placeholder_input_container';
if (field !== undefined) {
if (field.hasErrors()) className += ' error';
if (field.hasWarnings()) className += ' warning';
}
return (
<div className={className}>
<input
type={this.props.type}
name={this.props.name}
className="adaptive_input"
required
onChange={this.handle_change.bind(this)} />
<label
className="adaptive_placeholder"
alt={this.props.initial}
placeholder={this.props.focused} />
</div>
);
}
}
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
Name: 'No Name',
Value_1: '0',
Value_2: '0',
Display_Value: '0'
};
}
handle_text_input(e, new_text) {
this.form.validateFields(e.currentTarget);
this.setState({
Name: new_text
});
}
handle_value_1_input(e, new_value) {
this.form.validateFields(e.currentTarget);
if (this.form.isValid()) {
new_value = parseInt(new_value);
var updated_display = new_value + parseInt(this.state.Value_2);
updated_display = updated_display.toString();
this.setState({
Value_1: new_value,
Display_Value: updated_display
});
}
else {
this.setState({
Display_Value: 'Error'
});
}
}
handle_value_2_input(e, new_value) {
this.form.validateFields(e.currentTarget);
if (this.form.isValid()) {
new_value = parseInt(new_value);
var updated_display = parseInt(this.state.Value_1) + new_value;
updated_display = updated_display.toString();
this.setState({
Value_2: new_value,
Display_Value: updated_display
});
}
else {
this.setState({
Display_Value: 'Error'
});
}
}
render() {
return(
<div>
<h2>Name: {this.state.Name}</h2>
<h2>Value 1 + Value 2 = {this.state.Display_Value}</h2>
<FormWithConstraints ref={form => this.form = form} noValidate>
<Adaptive_Input
type="text"
name="name_input"
initial={'Name Input'}
focused={'Name Input'}
on_Input_Change={this.handle_text_input.bind(this)} />
<FieldFeedbacks for="name_input">
<FieldFeedback when="*" error />
<FieldFeedback when={value => !/^\w+$/.test(value)} warning>Should only contain alphanumeric characters</FieldFeedback>
</FieldFeedbacks>
<Adaptive_Input
type="number"
name="value_1_input"
initial={'Value 1'}
focused={'Value 1'}
on_Input_Change={this.handle_value_1_input.bind(this)} />
<FieldFeedbacks for="value_1_input">
<FieldFeedback when="*" />
</FieldFeedbacks>
<Adaptive_Input
type="number"
name="value_2_input"
initial={'Value 2'}
focused={'Value 2'}
on_Input_Change={this.handle_value_2_input.bind(this)} />
<FieldFeedbacks for="value_2_input">
<FieldFeedback when="*" />
</FieldFeedbacks>
</FormWithConstraints>
</div>
);
}
}
ReactDOM.render(<Form />, document.getElementById('app'));
.
ここで提案された解決策は、元のJSFIDDLEの近くに保つことを試みたようにハッキッシュされています。 React-Form-Constraintsを使用した適切なフォーム検証の場合は、 https:// github.com/tkrotoff/React-form-with-constraints#examples
onChange={this.handleChange.bind(this, "name")
メソッドと value={this.state.fields["name"]}
入力テキストフィールドと下のSPAN要素を作成するには、以下の例を参照してください。
export default class Form extends Component {
constructor(){
super()
this.state ={
fields: {
name:'',
email: '',
message: ''
},
errors: {},
disabled : false
}
}
handleValidation(){
let fields = this.state.fields;
let errors = {};
let formIsValid = true;
if(!fields["name"]){
formIsValid = false;
errors["name"] = "Name field cannot be empty";
}
if(typeof fields["name"] !== "undefined" && !fields["name"] === false){
if(!fields["name"].match(/^[a-zA-Z]+$/)){
formIsValid = false;
errors["name"] = "Only letters";
}
}
if(!fields["email"]){
formIsValid = false;
errors["email"] = "Email field cannot be empty";
}
if(typeof fields["email"] !== "undefined" && !fields["email"] === false){
let lastAtPos = fields["email"].lastIndexOf('@');
let lastDotPos = fields["email"].lastIndexOf('.');
if (!(lastAtPos < lastDotPos && lastAtPos > 0 && fields["email"].indexOf('@@') === -1 && lastDotPos > 2 && (fields["email"].length - lastDotPos) > 2)) {
formIsValid = false;
errors["email"] = "Email is not valid";
}
}
if(!fields["message"]){
formIsValid = false;
errors["message"] = " Message field cannot be empty";
}
this.setState({errors: errors});
return formIsValid;
}
handleChange(field, e){
let fields = this.state.fields;
fields[field] = e.target.value;
this.setState({fields});
}
handleSubmit(e){
e.preventDefault();
if(this.handleValidation()){
console.log('validation successful')
}else{
console.log('validation failed')
}
}
render(){
return (
<form onSubmit={this.handleSubmit.bind(this)} method="POST">
<div className="row">
<div className="col-25">
<label htmlFor="name">Name</label>
</div>
<div className="col-75">
<input type="text" placeholder="Enter Name" refs="name" onChange={this.handleChange.bind(this, "name")} value={this.state.fields["name"]}/>
<span style={{color: "red"}}>{this.state.errors["name"]}</span>
</div>
</div>
<div className="row">
<div className="col-25">
<label htmlFor="exampleInputEmail1">Email address</label>
</div>
<div className="col-75">
<input type="email" placeholder="Enter Email" refs="email" aria-describedby="emailHelp" onChange={this.handleChange.bind(this, "email")} value={this.state.fields["email"]}/>
<span style={{color: "red"}}>{this.state.errors["email"]}</span>
</div>
</div>
<div className="row">
<div className="col-25">
<label htmlFor="message">Message</label>
</div>
<div className="col-75">
<textarea type="text" placeholder="Enter Message" rows="5" refs="message" onChange={this.handleChange.bind(this, "message")} value={this.state.fields["message"]}></textarea>
<span style={{color: "red"}}>{this.state.errors["message"]}</span>
</div>
</div>
<div className="row">
<button type="submit" disabled={this.state.disabled}>{this.state.disabled ? 'Sending...' : 'Send'}</button>
</div>
</form>
)
}
}
. 最近、アプリで私のフォームを検証するために多くのソリューションを研究する週に過ごしました。私は最も見つめたすべてのものから始めましたが、私は予想されたように働いていた人を見つけることができませんでした。数日後、私は非常に新しい素晴らしいプラグインを見つけるまで、私はかなりイライラしました。 https://github.com/kettanaito/React-Advanced-form
開発者は、私の研究の後、私の視点から最も見つめたものになることを意味します。私はそれが助けることができることを願っています、そしてあなたは感謝するでしょう。
まだ別の問題と同じ問題 - form-container
NPM
過去にREDUX形式とフォルミクを使用しており、最近紹介されたフックを反応させ、カスタムフックを作成しました。確認して、フォーム検証をはるかに簡単にするかどうかを確認してください。
github: https://github.com/bluebill1049/React-hook-formed/a>
ウェブサイト: http://react-hook-form.now.sh
このアプローチでは、コントロール入力もできなくなりました。
下記の例:
import React from 'react'
import useForm from 'react-hook-form'
function App() {
const { register, handleSubmit, errors } = useForm() // initialise the hook
const onSubmit = (data) => { console.log(data) } // callback when validation pass
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input name="firstname" ref={register} /> {/* register an input */}
<input name="lastname" ref={register({ required: true })} /> {/* apply required validation */}
{errors.lastname && 'Last name is required.'} {/* error message */}
<input name="age" ref={register({ pattern: /\d+/ })} /> {/* apply a Refex validation */}
{errors.age && 'Please enter number for age.'} {/* error message */}
<input type="submit" />
</form>
)
}
. アプリケーションで同様の検証で複数のフィールドを持つことができます。そのような場合は、この検証を保つ共通コンポーネントフィールドを作成することをお勧めします。
例えば、アプリケーション内のいくつかの場所に必須のテキスト入力があると仮定しましょう。TextInputコンポーネントを作成できます。
constructor(props) {
super(props);
this.state = {
touched: false, error: '', class: '', value: ''
}
}
onValueChanged = (event) => {
let [error, validClass, value] = ["", "", event.target.value];
[error, validClass] = (!value && this.props.required) ?
["Value cannot be empty", "is-invalid"] : ["", "is-valid"]
this.props.onChange({value: value, error: error});
this.setState({
touched: true,
error: error,
class: validClass,
value: value
})
}
render() {
return (
<div>
<input type="text"
value={this.props.value}
onChange={this.onValueChanged}
className={"form-control " + this.state.class}
id="{this.props.id}"
placeholder={this.props.placeholder} />
{this.state.error ?
<div className="invalid-feedback">
{this.state.error}
</div> : null
}
</div>
)
}
.
、そのようなコンポーネントをアプリケーション内のどこにでも使用できます。
constructor(props) {
super(props);
this.state = {
user: {firstName: '', lastName: ''},
formState: {
firstName: { error: '' },
lastName: { error: '' }
}
}
}
onFirstNameChange = (model) => {
let user = this.state.user;
user.firstName = model.value;
this.setState({
user: user,
formState: {...this.state.formState, firstName: { error: model.error }}
})
}
onLastNameChange = (model) => {
let user = this.state.user;
user.lastName = model.value;
this.setState({
user: user,
formState: {...this.state.formState, lastName: { error: model.error }}
})
}
onSubmit = (e) => {
// submit logic
}
render() {
return (
<form onSubmit={this.onSubmit}>
<TextInput id="input_firstName"
value={this.state.user.firstName}
onChange={this.onFirstNameChange}
required = {true}
placeholder="First name" />
<TextInput id="input_lastName"
value={this.state.user.lastName}
onChange={this.onLastNameChange}
required = {true}
placeholder="Last name" />
{this.state.formState.firstName.error || this.state.formState.lastName.error ?
<button type="submit" disabled className="btn btn-primary margin-left disabled">Save</button>
: <button type="submit" className="btn btn-primary margin-left">Save</button>
}
</form>
)
}
.
利益:
- 検証ロジック を繰り返さない
- あなたのフォームのコードは少ない - それはより読みやすい です
- その他の一般的な入力ロジックはコンポーネント に保存できます
- コンポーネントができるだけダムであるべきであることをReact Ruleに従います