I'd like to create a custom React hook that
- wraps a state (created with
useState), - runs a clean-up function up when the component unmounts,
- executes a custom setter logic that derives a value,
- and exports the custom setter and the internal state value.
export function useCustomState() {
const [value, setValue] = useState();
useEffect(() => {
return () => {
// do cleanup
};
}, [value]);
function customSetValue(newValue) {
if (value) {
// do cleanup for the previous value
}
const derivedValue = derive(newValue);
setValue(derivedValue);
}
return [value, customSetValue];
}
I can achieve this with the code above. My problem arises when I use the returned values in an useEffect hook as a dependency, since the returned custom setter is always a new function reference.
const Component = () => {
const [value, setValue] = useCustomState();
useEffect(
() => {
setValue(simpleValue);
},
[setValue],
);
return <p>{ value }</p>;
};
When I don't include the setter as a dependency of the useEffect, the re-rendering stops, since the dependency does not change after a render. I can omit that reference and disable eslint for the line. This is one solution.
I'd like to know whether it is possible to create a custom referentially stable setter function?
I also have tried using useMemo that stores the custom setter function, but the dependencies for the memo still include the internal value and setValue references, since I want to do clean-up and set the new derived value. If the derived value is not the same for the same input, the dependency cycle will result in infinite re-rendering.