【问题标题】:ReactJS - Infinite Loop calling Wrapped MethodReactJS - 无限循环调用包装方法
【发布时间】:2019-04-02 13:57:46
【问题描述】:

我遇到了无限循环的常见问题,我不知道为什么。

我正在使用 reactJS 16.5.2

当您在不允许的地方(例如在渲染方法中)编写 SetState 时,通常会发生循环。

我正在关注本指南:https://medium.com/@baphemot/understanding-reactjs-component-life-cycle-823a640b3e8d 关注这个问题。

我制作了几个 HOC(装饰器/包装器)组件,将通用方法集中在一个点上,使用道具将它们传播给每个孩子。

它通常可以完美运行。

我尝试在下面简化我的组件结构。

问题在于 FORM 及其子项。 其中一个输入有一个 DropDown ,必须使用上层 Wrapper 的方法填充。我将调用放在 componentDidMount 中(如上面的链接所示)。不幸的是,包装器 setState 似乎触发了对 FORM 组件的完整描述和重新构建。我在从 Wrapped 到表单的每个构造函数中都放了一个 console.log。只有 FORM 及其所有 INPUTS 被重新创建(而不是更新)。

因为每次都会触发 componentDidMountis,所以这个重新创建会产生一个无限循环。

我不知道如何解决这个问题。我检查了每个“键”属性,所有组件都有其唯一键。我在问你为什么 react recreate 而不是 update?

是由于父渲染中的表单构建方法吗?如果是这样,构建具有异步数据填充的表单的正确设计模式是什么?

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    简化您的生活,而不是创建一堆包装,只需创建一个container-component,它的功能相同。例如,您将创建一个关心datastatecontainer,然后将其及其方法共享给一个可重用的子component(如下所示,两者功能相同)。

    这与从 API 获取的数据完全相同。您将在componentDidMount 中检索数据,将其设置为state,然后将state 传递给可重用组件。

    您可以使用可重复使用的组件获得超细粒度。例如,唯一目的是提交表单的可重用按钮。或仅捕获 1 到 100 之间的数字的可重用输入,依此类推。

    如果您的组件嵌套严重,请考虑使用redux

    工作示例:https://codesandbox.io/s/x2ol8wmzrp

    containers/Form.js(容器组件)

    import React, { Component } from "react";
    import Fields from "../components/Fields";
    
    export default class Form extends Component {
      state = {
        buttonFields: [
          { id: "Apples", quantity: 1 },
          { id: "Strawberries", quantity: 1 },
          { id: "Grapes", quantity: 1 },
          { id: "Apricots", quantity: 1 }
        ]
      };
    
      handleButtonClick = id => {
        this.setState(prevState => ({
          buttonFields: prevState.buttonFields.map(
            item =>
              id === item.id ? { id, quantity: item.quantity + 1 } : { ...item }
          )
        }));
      };
    
      render = () => (
        <Fields
          {...this.state}
          onButtonClick={this.handleButtonClick}
          title="Container Component"
        />
      );
    }
    

    components/Fields.js(可重用组件)

    import React from "react";
    
    export default ({ buttonFields, onButtonClick, title }) => (
      <div className="container">
        <h1 style={{ textAlign: "center" }}>{title}</h1>
        {buttonFields.map(({ id, quantity }) => (
          <button
            style={{ marginRight: 10 }}
            className="uk-button uk-button-primary"
            key={id}
            onClick={() => onButtonClick(id)}
          >
            {id} ({quantity})
          </button>
        ))}
      </div>
    );
    

    containers/Wrapper.js(不必要的包装器)

    import React, { Component } from "react";
    
    export default WrappedComponent => {
      class Form extends Component {
        state = {
          buttonFields: [
            { id: "Apples", quantity: 1 },
            { id: "Strawberries", quantity: 1 },
            { id: "Grapes", quantity: 1 },
            { id: "Apricots", quantity: 1 }
          ]
        };
    
        handleButtonClick = id => {
          this.setState(prevState => ({
            buttonFields: prevState.buttonFields.map(
              item =>
                id === item.id ? { id, quantity: item.quantity + 1 } : { ...item }
            )
          }));
        };
    
        render = () => (
          <WrappedComponent
            {...this.state}
            onButtonClick={this.handleButtonClick}
            title="Wrapper"
          />
        );
      }
    
      return Form;
    };
    

    【讨论】:

      【解决方案2】:

      感谢 Matt Carlotta 的回答,我弄清楚了问题所在。

      在上图中,我过于简化了,所以我错过了一个重要的声明。

      在“FinalComponent”中,当我创建 SomeFormComponent 时,由于它的包装,我正在做这样的事情:

      renderForm()
      {
        var WrappedFormComponent = FormHOC(SomeFormComponent();
        return <WrappedFormComponent {...this.props} [...] />
      }
      

      很明显,使用这种语法,由于在 render 方法中调用了 renderForm 方法,Form 每次都会被实例化。

      解决方案非常简单。我将该行移到组件上方:

      const WrappedFormComponent = FormHOC(SomeFormComponent();
      export default class FinalComponent extends React.Component
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-02-01
        • 2021-09-24
        • 2016-10-22
        • 2019-04-07
        • 2020-05-03
        • 2017-03-06
        • 1970-01-01
        相关资源
        最近更新 更多