I agree your way doing this works perfectly and you can even wrap it in a custom hook to reuse it.
Having said that (admitting there are cases where you don't want to run a stuff on mount but still on all re-renders !), is this hack improving our code ?
According to React guys, hooks allows us to separate concerns and avoid us to write stuff like :
componentDidMount(){// concern 1// concern 2// concern 3}componentDidUpdate(prevProps){if(prevProps.xxx!==this.props.xxx){// concern 2}if(prevProps.yyy!==this.props.yyy){// concern 3}// concern 4 (on each re-render because we can :) )}
which is imperative, redundant and difficult to simplify. Effects are made to be used atomically, to maintain good readability :
If the effect concernX have to be trigged only on updates right after any user action or async stuff, IMO you better should rely on your component scope (props, states, sometimes ref or context, ...). Ex :
const[selectedColor,setSelectedColor]=useState('blank');// or null or whateveruseEffect(()=>{if(selectedColor!=='blank'){// selectedCorolized unicorns popping}},[...]);
For readability purposes you can even put this in a custom hook and reuse the concern anywhere you want.
If the effect concernX have to be trigged only on updates right after any user action or async stuff, IMO you better should rely on your component scope (props, states, sometimes ref or context, ...). Ex:
So, if I'm understanding right what you're saying and especially this example, what you propose is to use something that already exists and that we're already monitoring to decide whether an effect hook should execute or not (and play with how that something has been initialised), rather than creating a specific reference to know whether the component has been mounted or not. Is that so?
Exactly, rely on data values ans data changes instead of component lifecycle. It seems to be the way hooks are designed.
Actually all your props should be observed and changes propagated in your component render flow, it's a really different approach than class components. Dan Abramov made a really detailed blog post about that here : overreacted.io/a-complete-guide-to...
Just an apetizer :
It’s only after I stopped looking at the useEffect Hook through the prism of the familiar class lifecycle methods that everything came together for me.
I'm still struggling with this approach. I have a really basic Class Component that calls an action creator (which is passed as a prop) if a particular prop is true and if another prop has changed, but only if that second prop isn't being changed for the first time.
The suggestion in the article by @savagepixie
got me around my issue, but I can't see how I could use @devdufutur
's suggestion (which sounds sensible but unachievable in my use case!):
Thanks Rudy, I believe you may have got me out of a jam with your suggestion of putting the if statement in useEffect. In my use case i need to watch for a change in the url as my app gets a redirect back from an api with a token.
( when path !== '/' means I have received a token from the api)
So now I can check it but only do something if I have the token, before I was getting a bit confused about needing useMemo or useRef.
Surprised I didn't think of your solution, perhaps I had it in my head that you shouldn't use conditionals inside useEffect.
So thanks again, and thanks SavagePixie for your post.
componentDidUpdate() does not run on initial render. However, useEffect always run on initial render. So, even if you pass dependencies in the array it will run for the first render. Thus it is not the exact mimic of ComponenentDidUpdate().
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
No, no, no folks don't do this ! It isn't the right way to use useEffect !
To mimic didMount juste pass [] as the second parameter of useEffect. To mimic didUpdate, pass all needed dependencies in the array.
But the best way to use useEffect is to avoid mimicking the old fashion lifecycle methods and understand the best coding practices hooks enables.
So, would you care to provide a quick example of how to make
useEffect
not execute after the first render but execute on subsequent renders?Or are you suggesting that one should (and indeed can) always find an alternative way that doesn't require to skip the
useEffect
on the first render?I agree your way doing this works perfectly and you can even wrap it in a custom hook to reuse it.
Having said that (admitting there are cases where you don't want to run a stuff on mount but still on all re-renders !), is this hack improving our code ?
According to React guys, hooks allows us to separate concerns and avoid us to write stuff like :
which is imperative, redundant and difficult to simplify. Effects are made to be used atomically, to maintain good readability :
If the effect concernX have to be trigged only on updates right after any user action or async stuff, IMO you better should rely on your component scope (props, states, sometimes ref or context, ...). Ex :
For readability purposes you can even put this in a custom hook and reuse the concern anywhere you want.
So, if I'm understanding right what you're saying and especially this example, what you propose is to use something that already exists and that we're already monitoring to decide whether an effect hook should execute or not (and play with how that something has been initialised), rather than creating a specific reference to know whether the component has been mounted or not. Is that so?
Exactly, rely on data values ans data changes instead of component lifecycle. It seems to be the way hooks are designed.
Actually all your props should be observed and changes propagated in your component render flow, it's a really different approach than class components. Dan Abramov made a really detailed blog post about that here : overreacted.io/a-complete-guide-to...
Just an apetizer :
It’s only after I stopped looking at the useEffect Hook through the prism of the familiar class lifecycle methods that everything came together for me.
“Unlearn what you have learned.” — Yoda
I like that approach
I'm still struggling with this approach. I have a really basic Class Component that calls an action creator (which is passed as a prop) if a particular prop is true and if another prop has changed, but only if that second prop isn't being changed for the first time.
The suggestion in the article by @savagepixie got me around my issue, but I can't see how I could use @devdufutur 's suggestion (which sounds sensible but unachievable in my use case!):
Any suggestions?
I guess your RequireLogon component could have been a custom hook...
I like that, primarily because what I had wasn't a "component" as such, but some sort of rule. This is certainly cleaner code. Thanks!
Thanks Rudy, I believe you may have got me out of a jam with your suggestion of putting the if statement in useEffect. In my use case i need to watch for a change in the url as my app gets a redirect back from an api with a token.
( when path !== '/' means I have received a token from the api)
So now I can check it but only do something if I have the token, before I was getting a bit confused about needing useMemo or useRef.
Surprised I didn't think of your solution, perhaps I had it in my head that you shouldn't use conditionals inside useEffect.
So thanks again, and thanks SavagePixie for your post.
componentDidUpdate() does not run on initial render. However, useEffect always run on initial render. So, even if you pass dependencies in the array it will run for the first render. Thus it is not the exact mimic of ComponenentDidUpdate().