React-将输入属性从defaultValue设置为value会触发无限循环

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React-将输入属性从defaultValue设置为value会触发无限循环相关的知识,希望对你有一定的参考价值。

我有一个容器组件,其中有一个子组件TranslateForm(其中有一个表单)和一个子组件AnswersTranslation。在容器组件中,我有一个函数changeTranslation,它会随道具一起发送:

  async changeTranslation(event, language) {
    const translationToUpdate = this.state.translations.find(translation => translation.languageCode === language);

    if (event.target.name === 'task') {
      translationToUpdate.taskText.to = event.target.value;
    } else {
      translationToUpdate.answers[event.target.name].to = event.target.value
    }

    this.setState({translations: this.state.translations.map(translation => translation.languageCode === language ? translationToUpdate : translation)});

    this.handleApiCall({...translationToUpdate});
 }

 handleApiCall(body) {
    if (this.timer !== null) {
      clearTimeout(this.timer);
    }

    this.timer = setTimeout(async () => {
      this.setState({saving: true});
      this.timer = null;
      await this.gateway.changeTranslation(body, this.props.match.params);
      this.setState({saving: false});
    }, 300);
}

而且我像道具一样将其发送下来:

onChange={(event, language) => this.changeTranslation(event, language)}

TranslateForm具有触发onKeyCapture事件的形式:

<form id={`translate-${translate}`} onKeyUpCapture={event => onChange(event, language)} autoComplete="off">
 <AnswersTranslation props={...props} />
</form>

[AnswersTranslation组件具有一个输入字段,我之前曾像这样设置defaultValue

                   {answers.map((answer, index) => {
                         <Input
                            name={`${index}`}
                            placeholder="Translate..."
                            className={classes.input}
                            defaultValue={answers[translate] !== null ? answers[translate] : ''}
                            disableUnderline={true}
                            inputProps={{
                                'aria-label': `answer-tekst-`,
                                maxLength: 100,
                            }}
                            disabled={translate === 'from'}
                        />
                    }

效果很好,但是它没有更新Input字段的值,所以我没有设置defaultValue而是这样设置值:

value={answers[translate] !== null ? answers[translate] : ''}

但是,一旦这样做,我得到了错误:

超过最大更新深度。当一个组件发生这种情况重复调用componentWillUpdate内的setState或componentDidUpdate。 React将嵌套更新的数量限制为防止无限循环。

为什么会这样?

答案

问题可能是因为当您获取translationToUpdate时,它仍然保留对状态的引用,因此基本上您是在直接对其进行修改。尝试使用setState的函数形式并调用handleApiCall作为回调,将从状态中检索值:

async changeTranslation(event, language) {
  const { name, value } = event.target;

  this.setState(state => ({
    translations: state.translations.map(translation => {
      if (translation.languageCode === language) {
        return name === 'task' ? {
          ...translation,
          taskText: {
            ...translation.taskText,
            to: value
          }
        } : {
          ...translation,
          answers: {
            ...translation.answers,
            [name]: value
          }
        }
      }
      return translation
    })
  }), () => this.handleApiCall(language)); // Callback after the state is set
}

handleApiCall = (language) => {
  const body = this.state.translations.find(translation => translation.languageCode === language);

  if (this.timer !== null) {
    clearTimeout(this.timer);
  }

  this.timer = setTimeout(async () => {
    this.setState({
      saving: true
    });
    this.timer = null;
    await this.gateway.changeTranslation(body, this.props.match.params);
    this.setState({
      saving: false
    });
  }, 300);
}

以上是关于React-将输入属性从defaultValue设置为value会触发无限循环的主要内容,如果未能解决你的问题,请参考以下文章

React 输入 defaultValue 不随状态更新

React defaultValue 导致过滤功能的行为与预期不同

react-hook-form 的 DefaultValues 未将值设置为 React JS 中的输入字段

React 中的模态对话框

React Material Multi Select 默认值未选中

将用户输入的值替换为 React 中分配有状态的值