Imagine this case.
A hook that receives an object and based on the object's properties does some computing and returns the result.
export const useTestHook = (someOject) => {
const [updated, set] = useState({ val1: null, val2: null });
useEffect(() => {
set({
val1: `${someOject.val1}_-`,
val2: `${someOject.val2}_-`,
})
}, [someOject]);
return updated;
}
The component using the hook has these values separated so a new object needs to be initialized so it can be passed to the hook. The result of the hook is then passed via some callback back to the parent.
function TestComp({ onChange, parentValue }) {
const [value1, setValue1] = useState('value1');
const [value2, setValue2] = useState('value2');
// since mergedValues is used as dependency of the hook I need to 'memoize' it otherwise it gets
// recreated on each re-render and will cycle
const mergedValues = useMemo(() => ({
val1: value1,
val2: value2
}), [value1, value2]);
const updatedVals = useTestHook(mergedValues);
useEffect(() => {
onChange(updatedVals);
}, [onChange, updatedVals]);
return (
<div>
Hello
</div>
);
}
The parent can do some other computing on that value and the result returns back to the child.
function App() {
const [value, set] = useState('value1');
return (
<TestComp onChange={set} parentValue={value} />
);
}
What is the correct way to handle object creation in a react component when the object is used as a dependency of some effect? Can be the useMemo
hook used for it?
const mergedValues = useMemo(() => ({
val1: value1,
val2: value2
}), [value1, value2]);
Official docs say "You may rely on useMemo as a performance optimization, not as a semantic guarantee." https://reactjs.org/docs/hooks-reference.html#usememo
Another way would be changing the hook's prop from an object to simple values and creating the object from these values inside hook's useEffect but this approach is no go for me.
What is the correct way to handle object creation in a react component when the object is used as a dependency of some effect? Can be the useMemo hook used for it?
Yes you can use useMemo
but there is one caveat. Since the docs say this:
You may rely on useMemo as a performance optimization, not as a semantic guarantee. In the future, React may choose to “forget” some previously memoized values and recalculate them on next rende
It means in some cases useMemo
can forget its stored value and still give you a new object, which could make useEffect
to fire if it uses that object as dependency, and that might be not what you want. But if your useEffect
is such that overfiring is not an issue, then this is not a problem.
You can also do something like this and there will be no need for useMemo
(assuming val1
and val2
are primitives):
useEffect(() => {
set({
val1: `${someOject.val1}_-`,
val2: `${someOject.val2}_-`,
})
}, [someOject.val1, someOject.val2]);