1 引言
使用 React Hooks 的时候,经常出现执行次数过多甚至死循环的情况,我们可以利用 use-what-changed 进行依赖分析,找到哪个变量引用一直在变化。
据一个例子,比如你尝试在 Class 组件内部渲染 Function 组件,Class 组件是这么写的:
class Parent extends React.PureComponent {
state = {
text: "text",
};
render() {
return <Child setText={(text) => this.setState({ text })} />;
}
}
子组件是这么写的:
const Child = ({ setText }) => {
useEffect(() => {
setText("ok");
}, [setText]);
return null;
};
那么恭喜你,写出了一个最简单的死循环。这个场景里,我们本意是利用 useEffect
调用 props.setText
更新父组件的 text
,但执行 props.setText
会导致父组件重渲染,由于父级 setText={(text) => this.setState({ text })}
的写法,每次重渲染拿到的 props.setText
引用都会变化,因此再次触发了 useEffect
回调执行,进而触发死循环。
仅仅打印出值是看不出变化的,引用的改变很隐蔽,为了判断是否变化还得存储上一次的值做比较,非常麻烦,use-what-changed 就是为了解决这个麻烦的。
2 精读
use-what-changed 使用方式如下:
function App() {
useWhatChanged([a, b, c, d]); // debugs the below useEffect
React.useEffect(() => {
// console.log("some thing changed , need to figure out")
}, [a, b, c, d]);
}
将参数像依赖数组一样传入,刷新页面就可以在控制台看到引用或值是否变化,如果变化,对应行会展示 ✅ 并打印出上次的值与当前值:

第一步是存储上一次依赖项的值,利用 useRef
实现:
function useWhatChanged(dependency?: any[]) {
const dependencyRef = React.useRef(dependency);
}
然后利用 useEffect
,对比 dependency
与 dependencyRef
的引用即可找到变化项:
React.useEffect(() => {
let changed = false;
const whatChanged = dependency
? dependency.reduce((acc, dep, index) => {
if (dependencyRef.current && dep !== dependencyRef.current[index]) {
changed = true;
const oldValue = dependencyRef.current[index];
dependencyRef.current[index] = dep;
acc[`"✅" ${index}`] = {
"Old Value": getPrintableInfo(oldValue),
"New Value": getPrintableInfo(dep),
};
return acc;
}
acc[`"⏺" ${index}`] = {
"Old Value": getPrintableInfo(dep),
"New Value": getPrintableInfo(dep),
};
return acc;
}, {})
: {};
if (isDevelopment) {
console.table(whatChanged);
}
}, [dependency]);
- 直接对比 deps 引用,不想等则将
changed
设为 true。 - 调试模式下,利用 console.table 打印出表格。
- 依赖项是 dependency,当依赖项变化时才打印 whatChanged。
以上就是其源码的核心逻辑,当然我们还可以简化输出,仅当有引用变化时才打印表格,否则只输出简单的 Log 信息:
if (isDevelopment) {
if (changed) {
console.table(whatChanged);
} else {
console.log(whatChanged);
}
}
babel 插件
最后 use-what-changed 还提供了 babel 插件,只通过注释就能打印 useMemo
、useEffect
等依赖变化信息。babel 配置如下:
{
"plugins": [
[
"@simbathesailor/babel-plugin-use-what-changed",
{
"active": process.env.NODE_ENV === "development" // boolean
}
]
]
}
使用方式简化为:
// uwc-debug
React.useEffect(() => {
// console.log("some thing changed , need to figure out")
}, [a, b, c, d]);
将 Hooks 的 deps 数组直接转化为 use-what-changed 的入参。
3 总结
use-what-changed 补充了 Hooks 依赖变化的调试方法,对于 React 组件重渲染分析可以利用 React Dev Tool,可以参考 精读《React 性能调试》。
还有哪些实用的 Hooks 调试工具呢?欢迎分享。
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=17923,转载请注明出处。
评论0