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

3

我在纯组件中有以下代码:

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

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

由于在JS中数组是对象,所以scheduleSheet !== prevScheduleSheet总是会被判定为true。那么为什么组件不会陷入无限循环更新的情况呢?我的意思是,每次'componentDidUpdate'运行时,它都会发现prevProps与新的props不相等,因此会更新状态,这将导致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
  ]
]

你能展示一下你的 this.props 是什么样子吗? - Code Maniac
@CodeManiac已添加。this.props.scheduleSheet指的是父组件的状态属性。 - user6898463
1
展示一下你如何传递props,为什么需要diff引用。 - Dennis Vash
@Skypho 这很奇怪,根据你在问题中发布的代码,不应该出现这种情况。可能有其他原因导致了这个问题,请你提供一个 CodePen 或创建一个最小可运行的代码片段来重现这个问题。 - Code Maniac
您可以在 CodeSandbox 上查看我分享的示例,看它是否回答了您的问题。 - Praneeth Paruchuri
属性不相等,然后在渲染之后,如果只有状态改变,它们就指向同一个数组。已经在 CodeSandbox 中更新了代码,请查看并告诉我。 - Praneeth Paruchuri
2个回答

1
你如何传递 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,不会由于“逻辑”原因导致无限循环。
此外,您使用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


你对此有误。PureComponent或Component并不重要。你可以查看我分享的示例并相应地进行更改以进行检查。 - Praneeth Paruchuri
你的示例属于“逻辑”原因,就像我解释的那样,去掉if语句看看会发生什么。https://codesandbox.io/s/ecstatic-hoover-swkm2 - Dennis Vash
其实,你是对的。我一直以为有一个if语句。 - Praneeth Paruchuri
1
你能编辑一下答案吗?我会点赞的。而且你的答案是正确的。 - Praneeth Paruchuri

-3

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

Dennis上面的答案是正确的。


当你这样做时

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

在第一次呈现时,道具不同,但是在状态更新之后,道具指向相同的数组,因为只有状态更改。
您可以从以下示例清楚地看到。


对象和数组的比较是浅层次的,有时会导致更新出现问题,但是当属性不改变时,数组是相同的,除非您每次使用具有相同值的新数组更新属性。

请查看以下示例:

Edit awesome-hofstadter-vw1sf

更新: 您可以取消注释componentDidUpdate中的代码,查看当props不改变时为什么它不会进入无限循环。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接