javascript - 在 useEffect 2nd 参数中使用对象,而无需将其字符串化为 JSON
问题描述
在 JS 中,两个对象不相等。
const a = {}, b = {};
console.log(a === b);
所以我不能使用useEffect
(React hooks)中的对象作为第二个参数,因为它总是被认为是假的(所以它会重新渲染):
function MyComponent() {
// ...
useEffect(() => {
// do something
}, [myObject]) // <- this is the object that can change.
}
这样做(上面的代码),每次重新渲染组件时都会产生运行效果,因为每次都认为对象不相等。
我可以通过将对象作为 JSON 字符串化值传递来“破解”它,但这有点脏 IMO:
function MyComponent() {
// ...
useEffect(() => {
// do something
}, [JSON.stringify(myObject)]) // <- yuck
有没有更好的方法来做到这一点并避免不必要的效果调用?
旁注:对象具有嵌套属性。效果必须在此对象内的每个更改上运行。
解决方案
您可以创建一个自定义挂钩来跟踪 a 中的先前依赖项数组,ref
并将对象与例如 Lodash 进行比较,isEqual
并且仅在它们不相等时才运行提供的函数。
例子
const { useState, useEffect, useRef } = React;
const { isEqual } = _;
function useDeepEffect(fn, deps) {
const isFirst = useRef(true);
const prevDeps = useRef(deps);
useEffect(() => {
const isFirstEffect = isFirst.current;
const isSame = prevDeps.current.every((obj, index) =>
isEqual(obj, deps[index])
);
isFirst.current = false;
prevDeps.current = deps;
if (isFirstEffect || !isSame) {
return fn();
}
}, deps);
}
function App() {
const [state, setState] = useState({ foo: "foo" });
useEffect(() => {
setTimeout(() => setState({ foo: "foo" }), 1000);
setTimeout(() => setState({ foo: "bar" }), 2000);
}, []);
useDeepEffect(() => {
console.log("State changed!");
}, [state]);
return <div>{JSON.stringify(state)}</div>;
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
推荐阅读
- reactjs - 从另一个组件访问状态
- arrays - 刷新问题:使用路径名和 url 数组在 React/Gatsby 中设置下一个和上一个链接
- javascript - 拆分字符串删除特殊字符,只在数组中写入相同的最后一个字符串
- r - 使用 mlr3 进行基准测试
- c# - 鼠标光标不起作用远程连接程序
- r - 如何绘制不同组的每个日期的平均值?
- python - 如何安装 Zipline-trader 而不会出错
- haskell - 你如何在 Haskell 中并行化从标准输入中读取的信息?
- mongodb - SpringBoot Mongorepository 没有正确保存实体属性集
- bash - 会话后不保存 Bash 别名