ReactJS-无限循环调用包装方法

时间:2018-10-29 15:30:26

标签: javascript reactjs

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

我正在使用reactJS 16.5.2

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

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

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

通常效果很好。

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

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

此重新创建会产生无限循环,因为每次都会触发componentDidMount。

我不知道该如何解决。我检查了每个“键”属性,所有组件都有其唯一的键。我问你为什么要重新创建而不是更新?

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

enter image description here

2 个答案:

答案 0 :(得分:2)

简化生活,而不是创建一堆包装器,只需创建一个将以相同方式运行的container-component即可。例如,您将创建一个关心containerdata的{​​{1}},然后与可重用子项state共享它和它的方法(如下所示,两者都可以一样)。

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

您可以对可重用组件进行超级细化。例如,一个唯一可重复使用的按钮是提交表单。或者是可重复使用的输入,只能捕获1到100之间的数字,依此类推。

如果组件嵌套过多,请考虑使用redux

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

containers / Form.js (容器组件)

state

components / Fields.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"
    />
  );
}

containers / Wrapper.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>
);

答案 1 :(得分:0)

感谢马特·卡洛塔(Matt Carlotta)的回答,我找出了问题所在。

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

在我创建SomeFormComponent的“ FinalComponent”中,由于其包装,我正在执行以下操作:

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

很明显,使用该语法,由于render方法中调用了renderForm方法,因此每次都会实例化Form。

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

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