This is a React style question.
TL;DR Take the set function from React's useState. If that function "changed" every render, what's the best way to use it in a useEffect, with the Effect running only one time?
Explanation We have a useEffect that needs to run once (it fetches Firebase data) and then set that data in application state.
Here is a simplified example. We're using little-state-machine, and updateProfileData is an action to update the "profile" section of our JSON state.
const MyComponent = () => {
const { actions, state } = useStateMachine({updateProfileData, updateLoginData});
useEffect(() => {
const get_data_async = () => {
const response = await get_firebase_data();
actions.updateProfileData( {user: response.user} );
};
get_data_async();
}, []);
return (
<p>Hello, world!</p>
);
}
However, ESLint doesn't like this:
React Hook useEffect has a missing dependency: 'actions'. Either include it or remove the dependency array
Which makes sense. The issue is this: actions changes every render -- and updating state causes a rerender. An infinite loop.
Dereferencing updateProfileData doesn't work either.
Is it good practice to use something like this: a single-run useEffect?
Concept code that may / may not work:
const useSingleEffect = (fxn, dependencies) => {
const [ hasRun, setHasRun ] = useState(false);
useEffect(() => {
if(!hasRun) {
fxn();
setHasRun(true);
}
}, [...dependencies, hasRun]);
};
// then, in a component:
const MyComponent = () => {
const { actions, state } = useStateMachine({updateProfileData, updateLoginData});
useSingleEffect(async () => {
const response = await get_firebase_data();
actions.updateProfileData( {user: response.user} );
}, [actions]);
return (
<p>Hello, world!</p>
);
}
But at that point, why even care about the dependency array? The initial code shown works and makes sense (closures guarantee the correct variables / functions), ESLint just recommends not to do it.
It's like if the second return value of React useState changed every render:
const [ foo, setFoo ] = useState(null);
// ^ this one
If that changed every render, how do we run an Effect with it once?