reactjs-跟踪为什么重新渲染React组件

是否有系统的方法来调试导致组件在React中重新渲染的原因? 我放置了一个简单的console.log()来查看它渲染了多少次,但是在弄清楚是什么导致组件多次渲染(即我的情况是4次)时遇到了麻烦。 是否存在可以显示时间轴和/或所有组件树渲染和顺序的工具?

jasan asked 2019-10-04T10:19:18Z
6个解决方案
63 votes

如果您想要一个简短的代码段,而没有任何外部依赖,我觉得这很有用

componentDidUpdate(prevProps, prevState) {
  Object.entries(this.props).forEach(([key, val]) =>
    prevProps[key] !== val && console.log(`Prop '${key}' changed`)
  );
  Object.entries(this.state).forEach(([key, val]) =>
    prevState[key] !== val && console.log(`State '${key}' changed`)
  );
}

这是我用来跟踪功能组件更新的小钩子

function useTraceUpdate(props) {
  const prev = useRef(props);
  useEffect(() => {
    const changedProps = Object.entries(props).reduce((ps, [k, v]) => {
      if (prev.current[k] !== v) {
        ps[k] = [prev.current[k], v];
      }
      return ps;
    }, {});
    if (Object.keys(changedProps).length > 0) {
      console.log('Changed props:', changedProps);
    }
    prev.current = props;
  });
}
Jacob R answered 2019-10-04T10:19:36Z
50 votes

这是一些React组件将重新渲染的实例。

  • 父组件重新渲染
  • 在组件内调用React.PureComponent。 这将触发以下组件生命周期方法false> shouldComponentUpdate> componentWillUpdate> render
  • 组件的React.PureComponent中的更改。这将触发false> shouldComponentUpdate> componentWillUpdate> render> componentDidUpdateconnectconnect方法在Redux存储中存在适用的更改时触发)
  • 呼叫React.PureComponent,类似于false

您可以通过在React.PureComponent内实施检查并在不需要时返回false来最大程度地减少组件的重新渲染。

另一种方法是使用React.PureComponent或无状态组件。 纯的和无状态的组件仅在其道具发生更改时才重新渲染。

jpdelatorre answered 2019-10-04T10:20:42Z
8 votes

@jpdelatorre的答案很好地强调了React组件可能重新呈现的一般原因。

我只是想更深入地研究一个实例:当道具发生变化时。 对导致React组件重新渲染的原因进行故障排除是一个常见问题,根据我的经验,跟踪该问题的很多时候都涉及确定哪些道具正在更改。

每当收到新的道具时,React组件都会重新渲染。 他们可以收到新的道具,例如:

prop1

或者如果prop1已连接到Redux存储:

function mapStateToProps (state) {
  return {
    prop3: state.data.get('savedName'),
    prop4: state.data.get('userCount')
  }
}

任何时候更改的值prop1prop2prop3prop4MyComponent的值都会重新呈现。 使用4个道具,将console.log(this.props)放在render块的开始位置,可以很容易地找到正在更改的道具。 但是,随着组件的复杂化和道具的增加,这种方法是站不住脚的。

这是一种有用的方法(为方便起见,使用lodash)来确定哪些属性更改导致了组件重新呈现:

componentWillReceiveProps (nextProps) {
  const changedProps = _.reduce(this.props, function (result, value, key) {
    return _.isEqual(value, nextProps[key])
      ? result
      : result.concat(key)
  }, [])
  console.log('changedProps: ', changedProps)
}

将此片段添加到您的组件中可以帮助发现导致可疑重新渲染的罪魁祸首,而且很多时候,这有助于阐明不必要的数据被管道传输到组件中的情况。

Cumulo Nimbus answered 2019-10-04T10:21:57Z
1 votes

上面的答案非常有帮助,以防万一有人正在寻找一种特定的方法来检测重新渲染的原因,那么我发现这个库redux-logger非常有用。

您可以做的是添加库并启用状态之间的差异(在文档中存在),例如:

const logger = createLogger({
    diff: true,
});

并在商店中添加中间件。

然后将(nextProps and this.props)放入要测试的组件的渲染功能中。

然后您可以运行您的应用程序并检查控制台日志。只要有日志显示状态(nextProps and this.props)之间的差异,您就可以确定那里是否确实需要渲染enter image description here

它将与上面的图像相似,并带有不同的键。

pritesh answered 2019-10-04T10:22:58Z
1 votes

现在在npm上可以使用此功能:

[https://www.npmjs.com/package/use-trace-update]

(公开,我发表了)

Damian Green answered 2019-10-04T10:23:39Z
0 votes

奇怪的是没有人给出这个答案,但是我发现它非常有用,特别是因为道具更改几乎总是嵌套在深处。

勾子迷们:

import deep_diff from "deep-diff";
const withPropsChecker = WrappedComponent => {
  return props => {
    const prevProps = useRef(props);
    useEffect(() => {
      const diff = deep_diff.diff(prevProps.current, props);
      if (diff) {
        console.log(diff);
      }
      prevProps.current = props;
    });
    return <WrappedComponent {...props} />;
  };
};

“老”学校的迷们:

import deep_diff from "deep-diff";
componentDidUpdate(prevProps, prevState) {
      const diff = deep_diff.diff(prevProps, this.props);
      if (diff) {
        console.log(diff);
      }
}

附言 我仍然更喜欢使用HOC(高阶分量),因为有时您在顶部分解了道具,而Jacob的解决方案不太适合

免责声明:与包裹所有者没有任何隶属关系。 只需单击数十次以尝试发现深层嵌套对象中的差异是很痛苦的。

ZenVentzi answered 2019-10-04T10:24:33Z
translate from https://stackoverflow.com:/questions/41004631/trace-why-a-react-component-is-re-rendering