【问题标题】:React - setting input prop from defaultValue to value triggers infinite loopReact - 将输入道具从 defaultValue 设置为 value 触发无限循环
【发布时间】:2019-11-15 15:38:06
【问题描述】:

我有一个容器组件,它有一个子组件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'}
                        />
                    }

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

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

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

已超过最大更新深度。这可能发生在组件 在 componentWillUpdate 内重复调用 setState 或 组件更新。 React 将嵌套更新的数量限制为 防止无限循环。

为什么会这样?

【问题讨论】:

  • changeTranslation 长什么样子?
  • 我会把它添加到问题中
  • 如果您从handleApiCall 中删除超时,问题是否仍然存在?
  • @Clarity 是的,我得到了同样的错误

标签: javascript reactjs


【解决方案1】:

问题可能是因为当你得到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);
}

【讨论】:

    猜你喜欢
    • 2015-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-02
    • 2019-10-25
    • 2016-10-23
    • 1970-01-01
    相关资源
    最近更新 更多