为什么不比较componentDidUpdate中的数组会导致无限循环?

时间:2019-09-10 15:28:35

标签: javascript arrays reactjs lifecycle

我的纯组件中包含以下代码:

  componentDidUpdate(prevProps) {
    const { scheduleSheet } = this.props;
    const { scheduleSheet: prevScheduleSheet } = prevProps;

    if (scheduleSheet !== prevScheduleSheet) {
      this.setState({ board: scheduleSheet });
    }
  }

由于数组是JS中的对象,因此scheduleSheet !== prevScheduleSheet将始终为true。那么为什么组件不会陷入无限的更新循环中呢?我的意思是,每次'componentDidUpdate'运行时,都会看到prevProps不等于新的,因此它将更新状态,该状态将运行componentDidUpdate ...那为什么不发生呢?


this.props.scheduleSheet的示例(指父组件的状态):

[
  null,
  null,
  [
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    true
  ],
  [
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    true
  ],
  [
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    true
  ],
  [
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    null,
    true
  ]
]

3 个答案:

答案 0 :(得分:0)

您如何通过props

const DEFAULT_SHEET = [];

export default class App extends React.Component {
  render() {
    return <Component scheduleSheet={DEFAULT_SHEET} />
  }
}

class Component extends React.Component {
  componentDidUpdate(prevProps) {
    const { scheduleSheet } = this.props;
    const { scheduleSheet: prevScheduleSheet } = prevProps;

    // Always false because the reference (props) never change.
    if (scheduleSheet !== prevScheduleSheet) {
      this.setState({ board: scheduleSheet });
    }
  }
}

在上面的示例中,引用没有更改,因此scheduleSheet !== prevScheduleSheet表达式始终为false,并且不会由于“逻辑”原因而引起inifite循环。


此外,您使用React.PureComponent,因此在这种情况下,您将不会获得无限循环:

                     // v NOT PURE COMPONENT, causes infinite loop and crash
class Component extends React.Component {
  componentDidUpdate(prevProps) {
    const { scheduleSheet } = this.props;
    const { scheduleSheet: prevScheduleSheet } = prevProps;

    console.log('scheduleSheet', scheduleSheet);
    console.log('prevScheduleSheet', prevScheduleSheet);
    this.setState({ board: prevScheduleSheet });
  }

  onChange = e => this.setState({ board: e.target.value });

  render() {
    return (
      <FlexBox>
        <Input value={this.state.board} onChange={this.onChange} />
      </FlexBox>
    );
  }
}

这是因为PureComponent实现了shouldComponentUpdate并具有较浅的属性和状态比较,从而防止了“不必要的渲染”。

Edit Q-57873953-PureComponent,ComponentDidUpdate

答案 1 :(得分:-3)

来自react docs

  

您可以在componentDidUpdate()中立即调用setState(),但请注意   必须将其包装在上面示例中所示的条件下,或者   您将导致无限循环。 这还会导致额外的重新渲染,尽管用户看不到它,但是会影响组件的性能。

这意味着:

  1. 仅当您不使用条件if (scheduleSheet !== prevScheduleSheet)
  2. 时,才会导致无限循环
  3. 当react执行额外的重新渲染(由setState中的componentDidMount引起的渲染)时,道具已经更新,因此prevPropsthis.props相同,因此这次条件将不成立,并且更新结束。

答案 2 :(得分:-3)

编辑: 我猜错了,假设代码中有if (scheduleSheet !== prevScheduleSheet) {

丹尼斯的答案是正确的。


执行此操作

if (scheduleSheet !== prevScheduleSheet) {
      this.setState({ board: scheduleSheet });
    }

道具在第一个渲染中是不同的,但是在状态更新之后,道具仅指向同一数组,因为只有状态会改变。
您可以从以下示例中清楚地看到这一点。


对象和数组比较浅,有时会与更新混淆,但是当props不变时,数组是相同的,除非您每次使用具有相同值的新数组更新props。

查看此示例:

Edit awesome-hofstadter-vw1sf

更新: 您可以在componentDidUpdate中取消对代码的注释,并查看inifite循环以及为什么在道具不变的情况下它不会显示。