redux-form
とブラー検証を使用しています。入力要素に最初の文字を入力すると、フォーカスが失われ、入力を続行するにはもう一度クリックする必要があります。これは最初の文字でのみ行われます。後続の文字タイプは引き続きフォーカスされます。これが私の基本的なサインインフォームの例です:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import * as actions from '../actions/authActions';
require('../../styles/signin.scss');
class SignIn extends Component {
handleFormSubmit({ email, password }) {
this.props.signinUser({ email, password }, this.props.location);
}
renderAlert() {
if (this.props.errorMessage) {
return (
<div className="alert alert-danger">
{this.props.errorMessage}
</div>
);
} else if (this.props.location.query.error) {
return (
<div className="alert alert-danger">
Authorization required!
</div>
);
}
}
render() {
const { message, handleSubmit, prestine, reset, submitting } = this.props;
const renderField = ({ input, label, type, meta: { touched, invalid, error } }) => (
<div class={`form-group ${touched && invalid ? 'has-error' : ''}`}>
<label for={label} className="sr-only">{label}</label>
<input {...input} placeholder={label} type={type} className="form-control" />
<div class="text-danger">
{touched ? error: ''}
</div>
</div>
);
return (
<div className="row">
<div className="col-md-4 col-md-offset-4">
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))} className="form-signin">
<h2 className="form-signin-heading">
Please sign in
</h2>
{this.renderAlert()}
<Field name="email" type="text" component={renderField} label="Email Address" />
<Field name="password" type="password" component={renderField} label="Password" />
<button action="submit" className="btn btn-lg btn-primary btn-block">Sign In</button>
</form>
</div>
</div>
);
}
}
function validate(values) {
const errors = {};
if (!values.email) {
errors.email = 'Enter a username';
}
if (!values.password) {
errors.password = 'Enter a password'
}
return errors;
}
function mapStateToProps(state) {
return { errorMessage: state.auth.error }
}
SignIn = reduxForm({
form: 'signin',
validate: validate
})(SignIn);
export default connect(mapStateToProps, actions)(SignIn);
これは、レンダリングするたびにrenderField
を新しいコンポーネントとして再定義しているために発生します。つまり、newコンポーネントからReact so元のものをアンマウントし、新しいものを再マウントします。
あなたはそれを持ち上げる必要があります:
const renderField = ({ input, label, type, meta: { touched, invalid, error } }) => (
<div class={`form-group ${touched && invalid ? 'has-error' : ''}`}>
<label for={label} className="sr-only">{label}</label>
<input {...input} placeholder={label} type={type} className="form-control" />
<div class="text-danger">
{touched ? error: ''}
</div>
</div>
);
class SignIn extends Component {
...
render() {
const { message, handleSubmit, prestine, reset, submitting } = this.props;
return (
<div className="row">
<div className="col-md-4 col-md-offset-4">
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))} className="form-signin">
<h2 className="form-signin-heading">
Please sign in
</h2>
{this.renderAlert()}
<Field name="email" type="text" component={renderField} label="Email Address" />
<Field name="password" type="password" component={renderField} label="Password" />
<button action="submit" className="btn btn-lg btn-primary btn-block">Sign In</button>
</form>
</div>
</div>
);
}
}
...
@riscarrottが述べたように、コンポーネントクラスの外にrenderField
を置きます。
しかし、私はまだ焦点を失っています..そして、テストした後、カリー化された関数(別の関数を返し、要素を直接返さない)を使用しているため、再レンダリングが行われたと結論付けました。
const const renderField = (InputComponent = 'input') => ({ input, label, type, meta: { touched, invalid, error } }) => (
<div class={`form-group ${touched && invalid ? 'has-error' : ''}`}>
<label for={label} className="sr-only">{label}</label>
<InputComponent {...input} placeholder={label} type={type} className="form-control" />
<div class="text-danger">
{touched ? error: ''}
</div>
</div>
);
次に、renderField
がカリー化された関数の場合:
//.....
<Field name="email" type="text" component={renderField('input')} label="Email Address" />
<Field name="desc" component={renderField('textarea')} label="Email Address" />
// outside component class
const InputField = renderField('input');
const TextAreaField = renderField('textarea');
// inside component class
<Field name="email" type="text" component={InputField} label="Email Address" />
<Field name="desc" component={TextAreaField} label="Email Address" />
私も同じ問題を抱えていました。 createForms()のストアにreactreduxフォームを追加したときに解決しました。
export const ConfigureStore = () => {
const store = createStore(
combineReducers({
tasks: Tasks,
task: Task,
image: Image,
admin: Admin,
pageId: PageID,
fieldValues: FieldValues,
formValues: FormValues,
...createForms({
createTask: initialTask,
editTask: initialEditTask
})
}),
applyMiddleware(thunk, logger)
);
return store;
}
これは、レンダー関数内にスタイル付きコンポーネントを定義した場合にも発生する可能性があります。クラス外で定義する必要があります。このような:
const Row = styled.div`
justify-content:center;
`;
const Card = styled.div`
width:18rem;
padding:1rem;
`;
class Login extends Component{