Monday, June 3, 2024
 Popular · Latest · Hot · Upcoming
71
rated 0 times [  77] [ 6]  / answers: 1 / hits: 159383  / 6 Years ago, tue, january 8, 2019, 12:00:00

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?


More From » reactjs

 Answers
53

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.


[#52808] Friday, January 4, 2019, 6 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
cody

Total Points: 679
Total Questions: 111
Total Answers: 111

Location: Czech Republic
Member since Thu, Aug 11, 2022
2 Years ago
;