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)]) // <- yuck
Is 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.
Example
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With