示例 const { useState, useEffect, useRef } = React;const { isEqual } = _;function useDeepEffect(fn, deps) { const isFirst = useRef(true); const prevDeps = useRef(deps); useEffect(() => { const isSame = prevDeps.current.every((obj, index) => isEqual(obj, deps[index]) ); if (isFirst.current || !isSame) { fn(); } isFirst.current = false; prevDeps.current = deps; }, 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>In JS two objects are not equals.const a = {}, b = {};console.log(a === b);So I can't use an object in useEffect (React hooks) as a second parameter since it will always be considered as false (so it will re-render):function MyComponent() { // ... useEffect(() => { // do something }, [myObject]) // <- this is the object that can change.}Doing this (code above), results in running effect everytime the component re-render, because object is considered not equal each time.I can "hack" this by passing the object as a JSON stringified value, but it's a bit dirty IMO:function MyComponent() { // ... useEffect(() => { // do something }, [JSON.stringify(myObject)]) // <- yuckIs there a better way to do this and avoid unwanted calls of the effect?Side note: the object has nested properties. The effects has to run on every change inside this object. 解决方案 You could create a custom hook that keeps track of the previous dependency array in a ref and compares the objects with e.g. Lodash isEqual and only runs the provided function if they are not equal.Exampleconst { useState, useEffect, useRef } = React;const { isEqual } = _;function useDeepEffect(fn, deps) { const isFirst = useRef(true); const prevDeps = useRef(deps); useEffect(() => { const isSame = prevDeps.current.every((obj, index) => isEqual(obj, deps[index]) ); if (isFirst.current || !isSame) { fn(); } isFirst.current = false; prevDeps.current = deps; }, 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> 这篇关于在useEffect第二个参数中使用对象,而不必将其字符串化为JSON的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云! 06-20 21:13