4 ms·
> While you can useEffect(fn, []), it’s not an exact equivalent. Unlike componentDidMount, it will capture props and state. So even inside the callbacks, you’ll
by ng12 8y ago
> While you can useEffect(fn, []), it’s not an exact equivalent. Unlike componentDidMount, it will capture props and state. So even inside the callbacks, you’ll see the initial props and state.
In my experience this is a fairly common source of confusion. People have a tendency to write things like:
useEffect(() => {
const unsub = subscribeToThing(thing => handleThing(props.id, thing))
return () => unsub()
}, [])
This looks pretty good except it's broken if props.id changes. handleThing() will always be called with the first props.id.
I'm the defacto React tutor at my company and issues like this make me pause before recommending new React devs to use hooks. useState is awesome and feels more natural to people than setState(). useEffect seems similarly simple but the subtleties can catch you.
- snek 8y agoI'd be wary to encourage useState. It seems too easy to accidentally use in loops/callbacks/etc where your state would then break because react tracks it via call order instead of call site.
- sophiebits 8y agoThe rule about unconditional calls tends to sound weird (I personally found it very strange when I first saw it), but in my experience, people do not have a hard time following it – it’s very rare to want a variable number of state fields, for example. If you do end up making a mistake, React has both lint rules provided and runtime checks to catch any errors. But from watching many people learn and use Hooks, we haven’t seen it to be a problem in practice.
- littlecranky67 8y agoYou don't use useState to set the state, you use useState() to GET back a function that can mutate the state. And this function is safe to call in a loop or conditional. When using hooks, yes, you have to remember not to call any use* function inside loops or conditionals (or use the linter plugins for that). Besides that, hardly any room for errors.
- sophiebits 8y agoThe lint rule Dan mentions (eslint-plugin-react-hooks/exhaustive-deps) will catch errors like this. It’s also worth noting that most class components people write don’t handle all prop updates correctly – Hooks tend to be slightly harder at first but tend to have fewer pitfalls in edge cases, especially if you stick to the rules (which there are lint rules to enforce).
- snek 8y agoBut there's something to be said about needing a lint rule for the API to be safely used.
- korm 8y agoTo play devil's advocate, this has always been the case with React. Newbies always mutate props or use setState incorrectly or in the wrong lifecycle methods. We've relied on linting to solve this for a long time now.
- blankaccount 8y agoThe nice thing about functional programming is that you can reason about execution and write lint rules to fix pitfalls that you can't detect with imperative programming.
- danabramov 8y agoI think the article touches on that point. Specifically, the lint rule points out a problem that a class implementation would also likely have. Except that you can’t easily lint the class implementation in a similar way. The lint rule is not to appease React. It’s to show you where a component doesn’t handle updates. This is already very common with classes but those issues tend to stay unnoticed.
- ng12 8y agoUnfortunately we use tslint so we'd have to add eslint just for this. > It’s also worth noting that most class components people write don’t handle all prop updates correctly I'm very guilty of this however I'm usually being intentionally lazy and assuming that a certain prop won't ever update. With useEffect it usually happens by mistake.