I am using react useEffect
hooks and checking if an object has changed and only then run the hook again.
My code looks like this.
const useExample = (apiOptions) => { const [data, updateData] = useState([]); useEffect(() => { const [data, updateData] = useState<any>([]); doSomethingCool(apiOptions).then(res => { updateData(response.data); }) }, [apiOptions]); return { data }; };
Unfortunately it keeps running as the objects are not being recognised as being the same.
I believe the following is an example of why.
const objA = { method: 'GET' } const objB = { method: 'GET' } console.log(objA === objB)
Perhaps running JSON.stringify(apiOptions)
works?
Advertisement
Answer
Use apiOptions
as state value
I’m not sure how you are consuming the custom hook but making apiOptions
a state value by using useState
should work just fine. This way you can serve it to your custom hook as a state value like so:
const [apiOptions, setApiOptions] = useState({ a: 1 }) const { data } = useExample(apiOptions)
This way it’s going to change only when you use setApiOptions
.
Example #1
import { useState, useEffect } from 'react'; const useExample = (apiOptions) => { const [data, updateData] = useState([]); useEffect(() => { console.log('effect triggered') }, [apiOptions]); return { data }; } export default function App() { const [apiOptions, setApiOptions] = useState({ a: 1 }) const { data } = useExample(apiOptions); const [somethingElse, setSomethingElse] = useState('default state') return <div> <button onClick={() => { setApiOptions({ a: 1 }) }}>change apiOptions</button> <button onClick={() => { setSomethingElse('state') }}> change something else to force rerender </button> </div>; }
Alternatively
You could write a deep comparable useEffect
as described here:
function deepCompareEquals(a, b){ // TODO: implement deep comparison here // something like lodash // return _.isEqual(a, b); } function useDeepCompareMemoize(value) { const ref = useRef() // it can be done by using useMemo as well // but useRef is rather cleaner and easier if (!deepCompareEquals(value, ref.current)) { ref.current = value } return ref.current } function useDeepCompareEffect(callback, dependencies) { useEffect( callback, dependencies.map(useDeepCompareMemoize) ) }
You can use it like you’d use useEffect
.