是否有系统的方法来调试导致组件在 React 中重新渲染的原因?我放了一个简单的 console.log() 来查看它渲染了多少次,但是我无法弄清楚是什么导致组件多次渲染,即在我的情况下(4 次)。是否存在显示时间线和/或所有组件树渲染和顺序的工具?
跟踪 React 组件重新渲染的原因
如果你想要一个没有任何外部依赖的简短片段,我觉得这很有用
componentDidUpdate(prevProps, prevState) {
Object.entries(this.props).forEach(([key, val]) =>
prevProps[key] !== val && console.log(`Prop '${key}' changed`)
);
if (this.state) {
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;
});
}
// Usage
function MyComponent(props) {
useTraceUpdate(props);
return <div>{props.children}</div>;
}
以下是 React 组件将重新渲染的一些实例。
- 父组件重新渲染
this.setState()
在组件内调用。这将触发以下组件生命周期方法shouldComponentUpdate
>componentWillUpdate
>render
>componentDidUpdate
- 组件的
props
. 这将触发componentWillReceiveProps
>shouldComponentUpdate
>componentWillUpdate
>render
>componentDidUpdate
(当 Redux 存储中有适用的更改时触发此connect
方法react-redux
) - 调用
this.forceUpdate
类似于this.setState
您可以通过在内部实现检查shouldComponentUpdate
并false
在不需要时返回来最小化组件的重新渲染。
另一种方法是使用React.PureComponent
或无状态组件。纯组件和无状态组件仅在其 props 发生更改时重新渲染。
您可以使用 React Devtools 分析器工具检查组件(重新)渲染的原因。无需更改代码。请参阅React团队的博文Introducing the React Profiler。
首先,转到设置 cog > profiler,然后选择“记录每个组件呈现的原因”
@jpdelatorre 的回答非常适合强调 React 组件可能重新渲染的一般原因。
我只是想更深入地研究一个实例:when props change。对导致 React 组件重新渲染的原因进行故障排除是一个常见问题,根据我的经验,很多时候追踪这个问题涉及确定哪些props正在改变。
React 组件在收到新的 props 时会重新渲染。他们可以获得新props,例如:
<MyComponent prop1={currentPosition} prop2={myVariable} />
或者如果MyComponent
连接到 redux 存储:
function mapStateToProps (state) {
return {
prop3: state.data.get('savedName'),
prop4: state.data.get('userCount')
}
}
任何时候的valueprop1
,prop2
,prop3
,或prop4
改变MyComponent
将重新呈现。使用 4 个props,通过console.log(this.props)
在render
块的开头放置一个来追踪哪些props正在改变并不难。但是随着组件越来越复杂,props越来越多,这种方法是站不住脚的。
这是一个有用的方法(为了方便使用lodash)来确定哪些 prop 更改导致组件重新渲染:
componentWillReceiveProps (nextProps) {
const changedProps = _.reduce(this.props, function (result, value, key) {
return _.isEqual(value, nextProps[key])
? result
: result.concat(key)
}, [])
console.log('changedProps: ', changedProps)
}
将此代码片段添加到您的组件中可以帮助揭示导致可疑重新渲染的罪魁祸首,而且很多时候这有助于阐明通过管道传输到组件中的不必要数据。
奇怪的是没有人给出这个答案,但我发现它非常有用,尤其是因为props更改几乎总是深度嵌套的。
勾搭粉丝:
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);
}
}
PS 我仍然更喜欢使用 HOC(高阶组件),因为有时你在顶部解构了你的props,而雅各布的解决方案并不适合
免责声明:与包所有者没有任何关系。只需单击数十次以尝试发现深层嵌套对象中的差异是一种痛苦。