Validation 使用redux form I';我在键入第一个字符后失去了焦点

Validation 使用redux form I';我在键入第一个字符后失去了焦点,validation,reactjs,redux,redux-form,Validation,Reactjs,Redux,Redux Form,我正在使用redux表单和模糊验证。在我将第一个字符键入输入元素后,它会失去焦点,我必须再次单击以继续键入。它只对第一个字符执行此操作。后续字符类型仍然是焦点。以下是我的基本登录表单示例: import React, { Component } from 'react'; import { connect } from 'react-redux'; import { Field, reduxForm } from 'redux-form'; import * as actions from '.

我正在使用
redux表单
和模糊验证。在我将第一个字符键入输入元素后,它会失去焦点,我必须再次单击以继续键入。它只对第一个字符执行此操作。后续字符类型仍然是焦点。以下是我的基本登录表单示例:

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);
import React,{Component}来自'React';
从'react redux'导入{connect};
从“redux form”导入{Field,reduxForm};
从“../actions/authActions”导入*作为操作;
需要('../styles/signin.scss');
类签名扩展组件{
handleFormSubmit({电子邮件,密码}){
this.props.signUser({email,password},this.props.location);
}
renderAlert(){
如果(此.props.errorMessage){
返回(
{this.props.errorMessage}
);
}else if(this.props.location.query.error){
返回(
需要授权!
);
}
}
render(){
const{message,handleSubmit,prestine,reset,submiting}=this.props;
const renderField=({input,label,type,meta:{topped,invalid,error}})=>(
{label}
{触摸?错误:“”
);
返回(
请登录
{this.renderAlert()}
登录
);
}
}
函数验证(值){
常量错误={};
如果(!values.email){
errors.email='输入用户名';
}
如果(!values.password){
errors.password='输入密码'
}
返回错误;
}
函数MapStateTops(状态){
返回{errorMessage:state.auth.error}
}
SignIn=reduxForm({
表格:'签名',
验证:验证
})(签名);
导出默认连接(MapStateTrops,actions)(登录);

之所以会发生这种情况,是因为每次渲染时都将
renderField
定义为一个新组件,这意味着它看起来像一个新组件,因此会卸载原始组件并重新装载新组件

你需要把它吊起来:

const renderField=({input,label,type,meta:{topped,invalid,error}})=>(
{label}
{触摸?错误:“”
);
类签名扩展组件{
...
render(){
const{message,handleSubmit,prestine,reset,submiting}=this.props;
返回(
请登录
{this.renderAlert()}
登录
);
}
}
...

如@riscarrott所述,将
renderField
置于组件类之外

但是我仍然在失去注意力。。测试后,我得出结论,重新渲染是因为使用了curried函数(返回另一个函数,而不是返回element.directly)

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>
    );
const const renderField=(InputComponent='input')=>({input,label,type,meta:{touched,invalid,error}})=>(
{label}
{触摸?错误:“”
);
然后,如果您的
renderField
是一个常用函数:


然后,不要做我也有同样的问题。当我将react redux表单添加到createForms()中的存储时,我解决了这个问题:

export const ConfigureStore=()=>{
const store=createStore(
组合传感器({
任务:任务,
任务:任务,
图像:图像,
管理员:管理员,
pageId:pageId,
字段值:字段值,
formValues:formValues,
…创建表单({
createTask:initialTask,
editTask:initialEditTask
})
}),
applyMiddleware(thunk,记录器)
);
退货店;

}
对我有效的是将基于函数的组件重构为基于类的组件,因为InputForm组件的行为很奇怪。每次更改每个输入的值时,即使将每个输入类型拆分为单独的组件,它们都会重新提交。除了将主组件更改为基于类之外,没有其他需要修复的问题。我想这可能是由redux表单本身造成的。

如果在渲染函数中定义了样式化组件,也可能发生这种情况。 您应该在类之外定义它们。 像这样:

const Row = styled.div`
    justify-content:center;
`;
const Card = styled.div`
    width:18rem;
    padding:1rem;
 `;
 class Login extends Component{

我也有同样的问题。通过将组件更改为类组件,我解决了我的问题,并从render()中删除了所有css样式配置。

我遇到了同样的问题,并且没有一个答案对我有效。 但多亏了Advem的回答,我才知道什么是错的: 我的表单需要手风琴UI,为此我在表单中添加了状态变量

const ConveyorNotificationSettingsForm = (props) => {
    const {handleSubmit, formValues, dirty, reset, submitting} = props;
    const [expandedSection, setExpandedSection] = useState(null);
...
只有一个展开节,其索引等于
expandedSection


我将手风琴提取到一个单独的功能组件并将
useState
移动到那里之后,问题就消失了。

实际上,这是功能组件的问题。我使用了一个redux形式的基于类的组件,解决了我的问题。我不知道确切的原因,但当我们输入第一个单词并失去焦点时,redux表单会重新呈现。只要您想使用redux表单,就可以使用基于类的组件

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);
类StreamCreate扩展了React.Component{
rendorInput(formProps){
返回;
}
render(){
返回(
)
}
}
导出默认reduxForm({
表单:“createStream”
})(创建);

Doh!谢谢我会试一试。谢谢,这对我来说很有效,即使有一个功能组件。这是一个解释得很好的答案,可能节省了我几个小时。谢谢你@abdennour!欢迎@rakitin