使用 redux-form 我在输入第一个字符后失去了焦点
Using redux-form I'm losing focus after typing the first character
我正在使用 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
重新定义为一个新组件,这意味着它看起来像 React 的 new 组件,所以它'我会卸载原来的并重新安装新的。
你需要把它举起来:
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
放在组件 class 之外。
但我仍然失去焦点..经过测试,我得出结论,重新渲染是因为使用了 curried 函数(return 另一个函数,而不是 return 元素 . 直接) .
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():
中将我的 React redux 表单添加到商店时解决了这个问题
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;
}
对我有用的是将 arrowFunction-based 组件重构为 class-based 组件作为 InputForm 组件的行为很奇怪。每次更改每个输入的值时,即使在将每个 inputType 拆分为单独的组件之后,它们也会重新渲染。除了将主要组件更改为基于 class 之外,别无他法。我猜想可能是redux-form本身造成的
如果您在渲染函数中定义了样式组件,也会发生这种情况。
您应该在 class 之外定义它们。
像这样:
const Row = styled.div`
justify-content:center;
`;
const Card = styled.div`
width:18rem;
padding:1rem;
`;
class Login extends Component{
我也遇到了同样的问题。我通过将组件更改为 Class 组件来解决我的问题,并且我从 render().
中删除了所有 css 样式配置
我遇到了同样的问题,none 的答案对我有用。
但是多亏了 Advem 的回答,我才知道可能出了什么问题:
我的表格需要手风琴 UI,为此我在其中添加了状态变量:
const ConveyorNotificationSettingsForm = (props) => {
const {handleSubmit, formValues, dirty, reset, submitting} = props;
const [expandedSection, setExpandedSection] = useState(null);
...
只有一个扩展部分,其索引等于 expandedSection
.
在 我将手风琴提取到一个单独的功能组件并将 useState
移到那里 之后,问题就消失了。
其实这是函数组件的问题。我使用了一个基于 class 的具有 redux 形式的组件,我的问题就解决了。我不知道确切的原因,但是当我们输入第一个单词并丢失焦点时,redux 表单会重新呈现。每当您想使用 redux 形式时,请使用基于 class 的组件。
class StreamCreate extends React.Component{
rendorInput(formProps){
return <input {...formProps.input} />;
}
render(){
return (
<Container maxWidth="lg">
<form action="">
<Field name="title" component={this.rendorInput}/>
<Field name="description" component={this.rendorInput} />
</form>
</Container>
)
}
}
export default reduxForm({
form: 'createStream'
})( StreamCreate);
我正在使用 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
重新定义为一个新组件,这意味着它看起来像 React 的 new 组件,所以它'我会卸载原来的并重新安装新的。
你需要把它举起来:
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
放在组件 class 之外。
但我仍然失去焦点..经过测试,我得出结论,重新渲染是因为使用了 curried 函数(return 另一个函数,而不是 return 元素 . 直接) .
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():
中将我的 React redux 表单添加到商店时解决了这个问题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;
}
对我有用的是将 arrowFunction-based 组件重构为 class-based 组件作为 InputForm 组件的行为很奇怪。每次更改每个输入的值时,即使在将每个 inputType 拆分为单独的组件之后,它们也会重新渲染。除了将主要组件更改为基于 class 之外,别无他法。我猜想可能是redux-form本身造成的
如果您在渲染函数中定义了样式组件,也会发生这种情况。 您应该在 class 之外定义它们。 像这样:
const Row = styled.div`
justify-content:center;
`;
const Card = styled.div`
width:18rem;
padding:1rem;
`;
class Login extends Component{
我也遇到了同样的问题。我通过将组件更改为 Class 组件来解决我的问题,并且我从 render().
中删除了所有 css 样式配置我遇到了同样的问题,none 的答案对我有用。 但是多亏了 Advem 的回答,我才知道可能出了什么问题: 我的表格需要手风琴 UI,为此我在其中添加了状态变量:
const ConveyorNotificationSettingsForm = (props) => {
const {handleSubmit, formValues, dirty, reset, submitting} = props;
const [expandedSection, setExpandedSection] = useState(null);
...
只有一个扩展部分,其索引等于 expandedSection
.
在 我将手风琴提取到一个单独的功能组件并将 useState
移到那里 之后,问题就消失了。
其实这是函数组件的问题。我使用了一个基于 class 的具有 redux 形式的组件,我的问题就解决了。我不知道确切的原因,但是当我们输入第一个单词并丢失焦点时,redux 表单会重新呈现。每当您想使用 redux 形式时,请使用基于 class 的组件。
class StreamCreate extends React.Component{
rendorInput(formProps){
return <input {...formProps.input} />;
}
render(){
return (
<Container maxWidth="lg">
<form action="">
<Field name="title" component={this.rendorInput}/>
<Field name="description" component={this.rendorInput} />
</form>
</Container>
)
}
}
export default reduxForm({
form: 'createStream'
})( StreamCreate);