Реагировать - Предупреждение: обновление было запланировано изнутри функции обновления

Я сталкиваюсь с множеством проблем с обновлением состояний в React для целей проверки, и всегда мое обновление состояния после рендеринга или чего-то в этом роде, в любом случае, я видел, что многие люди решают это, используя функцию обратного вызова в setState, но это всегда выдает следующее предупреждение.

Предупреждение: обновление (setState, replaceState или forceUpdate) было запланировано изнутри функции обновления. Функции обновления должны быть чистыми, без побочных эффектов. Рассмотрите возможность использования componentDidUpdate или обратного вызова.

Я пытался обновить внутри componentDidUpdate, но это привело к бесконечному циклу.

Это мой setState с функцией обратного вызова.

state = {
    index: 0,
    activeInput: '',
    errors: {
      error: false,
      errorNombre: false,
      errorCuil: false,
      errorEmail: false,
      errorContrasena: false,
      errorCalle: false,
      errorNumero: false,
      errorProvincia: false,
      errorLocalidad: false
  },
    values: {...this.props.initialValues}
  };

    _onChangeValue = (name, value) => {
        this.setState(prevState => {
          return {
            values: {
              ...prevState.values,
              [name]: value
            }
          }, this.validate(name)
        })
      };

И это функция проверки, это переключатель, так что я намного дольше, но проблема может быть в том, что в каждом случае есть другой setState внутри ...

validate = input => {

    switch(input){
      case 'nombre':
        let { nombre } = this.state.values
        let splitNombre = nombre.split(' ');

        if ( splitNombre.length > 1 && splitNombre[1].length === 0 || nombre.length === 0 || splitNombre.length === 1 ) {
          this.setState(prevState => ({
            errors: { ...prevState.errors, error: true, errorNombre: true }
          }));
        } else {
          this.setState(prevState => ({
            errors: { ...prevState.errors, error: false, errorNombre: false }
          }));
        }
        break

Поскольку это составной компонент, он немного беспорядочный, но вот файлы

Input.js

import React, { PureComponent } from 'react';

class Input extends PureComponent {
  _onChangeText = text => {
    this.props.onChangeValue(this.props.name, text);
  };

  render() {
    const { onChangeValue, name, ...rest } = this.props;
    return (
      <input {...rest} onChange={(event) => this._onChangeText(event.target.value)} />
    );
  }
}

export default Input;

Steps.js

import Botones from './Botones'

    export default class Step extends PureComponent {
        state = {}
        render() {
          return (
            <Fragment>

              {this.props.children({
                onChangeValue: this.props.onChangeValue,
                values: this.props.values,
                index: this.props.index,
                errors: this.props.errors
              })}

              <div>
            <Botones currentIndex={this.props.currentIndex}
                     prevStep={this.props.prevStep}
                     nextStep={this.props.nextStep}
                     onSubmit={this.props.onSubmit}
                     isLast={this.props.isLast}
                     isFirst={this.props.isFirst}
                     error={this.props.errors.error}    
            />

          </div>
        </Fragment>
      )
    }
  }

FirstStep.js

import Steps from './Steps';

export default class FirstStep extends Component {

    constructor(props){
        super(props)
        this.state = {}
    }

    render() {
        //console.log(this.props)
        return (
            <Fragment>
                <Steps level={this.props.index}/>
                <form onSubmit={this.onSubmit} className="mt90">
                    <div>
                        <label>Nombre completo</label>
                        <input type="text"
                               name="nombre"
                               placeholder="Escriba su nombre"
                               onChange={ event => this.props.onChangeText('nombre', event.target.value) }
                               value={this.props.values.nombre}
                               className={ `${ this.props.errors.errorNombre && "error-focus" }` }
                               />
                        { this.props.errors.errorNombre &&
                        <span className="error">No es un nombre completo</span> }
                    </div>
                    <div className="mt50">
                        <label>N° de CUIL</label>
                        <input type="text"
                               name="cuil"
                               placeholder="Ej.: 23-45678901-2"
                               onChange={ event => this.props.onChangeText('cuil', event.target.value) }
                               value={this.props.values.cuil}
                               className={ `${ this.props.errors.errorCuil && "error-focus" }` }
                               />
                        { this.props.errors.errorCuil &&
                        <span className="error">No es un CUIL válido</span> }
                    </div>
                </form>
            </Fragment>
        )
    }
}

App.js (имеет FirstStep в качестве дочернего компонента)

[...]
Render()
<RegisterBox.Step>
            { ({ values, onChangeValue, index, errors }) => (
              <FirstStep values={values} onChangeText={onChangeValue} index={index} errors={errors} />
            )}
          </RegisterBox.Step>
[...]

person Leandro Aranguez    schedule 10.08.2018    source источник
comment
Попробуйте переместить this.validate(name) за пределы вашего метода setState   -  person Adam Johnston    schedule 10.08.2018
comment
Это работает, но не проверяется в то же время, когда вы вводите ввод .. я имею в виду, когда мне нужно имя длиной 11, только когда я набираю 12 раз, проверяет, что все в порядке, я пытался это сделать, чтобы немедленно внести изменения потому что я не могу вызвать это в рендере (бесконечный цикл)   -  person Leandro Aranguez    schedule 10.08.2018


Ответы (2)


Похоже, вы допустили небольшую опечатку. Ваше решение должно выглядеть примерно так.

_onChangeValue = (name, value) => {
    this.setState(prevState => {
      return {
        values: {
          ...prevState.values,
          [name]: value
        }
      }
    }, () => this.validate(name));
  };

Обратите внимание, что при вызове this.validate на один набор скобок выведены. Во-вторых, он был заключен в анонимную функцию, так что его можно фактически использовать как обратный вызов.

Я полагаю, это привело бы к некоторому сбивающему с толку поведению. Из-за оператора запятой ваш setState не производил бы никаких обновлений значений, вместо этого обновлял бы состояние только с результатами вашей проверки!

person j ling    schedule 03.12.2018

Я думаю, вам нужно переосмыслить эту проблему. Чтобы убедиться, что мы идем в одном темпе, позвольте мне повторить несколько моментов.

Прежде всего setState является асинхронным и больше похоже на сигнал React для обновления объекта состояния и вызывает функции жизненного цикла React.

Вложенные setState не приветствуются, поскольку трудно понять поведение асинхронных вызовов.

Вам необходимо реструктурировать свои функции, чтобы избежать вложенных setState. Я не могу сделать это за вас в этом кратком ответе, и вы лучше всех знаете, как вы хотите это сделать. Одна вещь, на которую вам нужно обратить внимание, - это то, что иногда вы можете сериализовать setState вызовы, чтобы убедиться, что prevState, которое вы видите в этом текущем setState вызове, действительно из предыдущего вызова. Один из способов заставить его работать - заключить setState в Promise и использовать await/async для сериализации вызовов.

Надеюсь это немного поможет.

person Huy Doan    schedule 21.08.2018
comment
Хай Доан, я вроде как любитель, поэтому мои практики не очень хорошие, обещания могут решить проблему, я думаю, я попробую! Спасибо - person Leandro Aranguez; 23.08.2018