Используя редукс-форму, я теряю фокус после ввода первого символа

Я использую 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);

Ответ 1

Это происходит из-за того, что вы повторно определяете renderField как новый компонент при каждом рендеринге, что означает, что он выглядит как новый компонент для Реагирования, поэтому он будет отключать оригинальный и снова монтировать новый.

Вам нужно будет поднять его:

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>
    );
  }
}

...

Ответ 2

Как упоминал @riscarrott, поместите renderField вне класса компонента.

Но я все еще теряю фокус. И после тестирования я пришел к выводу, что повторная рендеринг выполняется из-за использования функции curried (напрямую возвращать другую функцию, а не возвращать элемент).

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" />

Ответ 3

У меня такая же проблема. Я решил это, когда я добавил свою форму редукции реакции в хранилище в createForms():

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;
}

Ответ 4

Для меня сработало рефакторинг компонента на основе arrowFunction в компонент на основе класса, так как поведение компонентов InputForm было странным. Каждый раз, когда значение каждого ввода было изменено, они все перерисовывались, даже после разделения каждого inputType на отдельные компоненты. Больше ничего не осталось, кроме как изменить основной компонент на классовый. Я предполагаю, что это может быть вызвано самой избыточной формой.