我一直在思考这个问题有一段时间了。我一直在和自己斗争,说"but this is how React works"
vs "but most people don't know"
。
对于我正在编写的一个库,用户需要向钩子提供一个配置对象,然后库“同步”这个配置对象并返回结果。
理想(简化)情况:
const myHook = (configObjectProvidedByUser, onError) => {
const [state, setState] = useState();
useEffect(() => {
let ignore = false;
doSomeSyncing(configObjectProvidedByUser)
.then((response) => {
if (!ignore) {
setState({ source: configObjectProvidedByUser, resolved: response });
}
})
.catch((error) => {
if (!ignore) {
setState({ source: configObjectProvidedByUser, error });
onError(error);
}
});
return () => {
ignore = true;
};
}, [configObjectProvidedByUser, onError]);
if (configObjectProvidedByUser === state?.source) {
return state;
}
return undefined;
};
这段代码按预期工作。但只有当实现者不每次都提供新的configObjectProvidedByUser
时。
实现者将编写以下代码:
// getSomeConfig returns a new object every time
myHook(getSomeConfig(), (error) => logError(error))
这会导致效果在每个渲染器上运行,因为一个新的对象被创建。我知道这是react的工作原理,我知道实现者可以使用useMemo
来记忆getSomeConfig
。但它也是一个像这样的真人程序。有什么方法可以防止这种编程风格吗?或者有人有任何其他关于如何处理这些情况的建议吗?
我想到的一个解决方案是使用lodash.isEqual
来比较configObjectProvidedByUser
。但是这会导致运行效果清理函数的问题,该函数仍然会被触发,忽略当前的异步操作。
1条答案
按热度按时间czfnxgou1#
我假设 “我想到的一个解决方案是使用lodash.isEqual来比较configObjectProvidedByUser。但是这会导致运行效果清理函数的问题,该函数仍然会被触发,忽略当前的异步操作。" 你的意思是在
useEffect
钩子内的IF语句中比较传入的配置值?解决这个问题的一个方法是不要求
useEffect
钩子比较对象,而是要求它比较一个字符串值,如下所示:https://codepen.io/crooy/pen/abRzoBd免责声明:这里有一个计算代价,JSON.stringify也有问题,因为它不能确保字段的顺序相同。
在这种情况下,除了Typescript中的一些强类型和良好的文档之外,没有什么可以保存你。还有另一种选择......也许有点不正统,你可以让钩子返回一个Subscribable/Observable/EventTarget示例。然而,我猜这只是 “just dont do that” 的变体😅。