10 ms·
A Visual Guide to React's useEffect (2021)
- jraph 4y agouseEffect should not be capitalized because it's a function name (I guess HN's title auto-mangling did this). While we are at it, I would suggest to specify in the submission title that it's about React, and it's also from 2021, so: A Visual Guide to React's useEffet hook (2021)
- iainmerrick 4y agoNot very visual for a visual guide.
- deleted 4y ago[deleted]
- bottlepalm 4y agoIt’s kind of funny how cryptic react can be. Very easy to miss that having an empty [] as a second parameter will result in completely different functionality. React is pretty nice overall, just why do we design things to be so unintuitive. Dark patterns.
- ajkjk 4y agoI think that particular choice was an unusually big mistake. Most of them are not so big. But I can't fathom why they made "empty array" cause no rerenders but "no array" cause all the rerenders.
- culi 4y agoThere's a few, rare, use-cases where you'd actually want this behavior. But I agree it's too easy to accidentally do this thing that should be an extreme edge case.
- sli 4y agoI've run into those cases a couple times before and my immediate thought was that it seems unwise for this one function to be used in both cases. There really ought to be something specifically intended for effects with no dependencies even if all it does is make the difference explicit. I'm not a fan of things that contain features that manifest like subtle traps because determining programmer intent is undecidable. That lesson was learned from PHP <=5.
- imbnwa 4y agoAt the very least make them separate functions
- ajkjk 4y agoYeah, that's what I'm saying. There's no reason they had to be the same thing.
- eyelidlessness 4y agoThis is why whenever I can (i.e. it’s not a breaking API change or it’s agreed on), I turn these implicit rules into explicit options named and documented as such in the code. Yeah it’s a little more to type, but it solves the “this isn’t obvious for good reasons” problem much better than a pair of defaults that you probably don’t even know how to look up.
- systoll 4y agouseEffect is treating undefined as meaning undefined. It makes perfect sense from inside of useEffect. If there are no dependencies ([]), the dependencies can never change, so React can always reuse the old effect. If the dependencies aren’t defined, there’s no way to tell if the old effect is OK, so React must always rebuild it. ** But `useEffect(()=>{})` doesn’t explicitly show that React will get `dependencies = undefined`, and in this case that’s unusually important. You could have ESlint force you to change that to `useEffect(()=>{}, undefined)`, I suppose…
- bottlepalm 4y agoYes we know how it works. What we’re saying is that it is a cryptic design. Just like the function returned from useEffect is used for unmounting the component. Not intuitive at all.
- darepublic 4y agothere is an eslint rule exhaustive-deps which really helps with this
- systoll 4y agoFor useMemo and useCallback, Typescript and exhaustive-hooks will both tell you to add a dependency array, because without it those hooks do nothing. For useEffect, exhaustive-hooks & Typescript say nothing, because a non-memoised Effect is a reasonable thing to write. It’s just not a great thing to write accidentally.
- purple_ferret 4y agoI'm pretty sure because it's basically an easy hack to recreate the behavior of componentDidMount.
- culi 4y agoI've found that people that learned class-based React first and then switched to modern function-based React often have more trouble with useEffect than people who learned functional components directly I think a big part of the problem is we need to stop selling useEffect as a replacement for the lifecycle methods of class based components. It also probably would've been a lot less confusing if we called it something like useSideEffect I think any react linting setup resolves most of the confusion but there's a lot of people that start off and don't even know how to set up lint rules for react. They should be a default in any react app imo
- luisgvv 4y agoI can second this... I inherited a huge pile of crap without a react lint ruleset and as soon as I put it in place there were ton of errors. The part I don't like about useEffect is that developers tend to overuse it and when they get stuck in infinite render loops you can see the whole mess it can lead to and how hard it can be to untangle monkey patched logic.
- orangepanda 4y ago> I've found that people that learned class-based React first and then switched to modern function-based React often have more trouble with useEffect than people who learned functional components directly I’d say its the opposite; people who used lifecycle methods know that useEffect and friends eliminates an entire class of bugs. People who started with hooks dont understand the problems it solved, and only see the quirks
- chrisbaker98 4y agoI'm far more experienced with React function components than with class components, so I'm curious, what are some of the problems with class components and how did hooks solve them?
- spion 4y agoThis was not the only design possible. The main problem with lifecycle methods was that you couldn't have multiple of them. There is absolutely nothing about the design of React that necessitated hooks to fix that issue. You could have this API this.addListener('mount', () => { // do things on mount // return cleanup to be called on unmount return () => cleanup() }) called from the constructur of a component. With this you could setup multiple listeners and make sure they're all cleaned up. But no, the syntax wasn't "clean" (you'd pass `this` as an argument to the "custom hooks" equivalent"), so instead we got this error-prone order-dependent design that doesn't allow conditional execution and runs on every render.
- technion 4y agoThe irony is that the whole sell for hooks were that they were easier than classes, which people argued were too hard to reason with. There has been so much hype for how much easier things are with hooks and yet here we are.
- kabes 4y agoI agree it's not easier, but I thought the main argument was better composability. And I think that it achieves that goal quite well.
- nnurmanov 4y agoWith hooks we have now to dialects of the same framework. It is so confusing some time!
- rhaway84773 4y agoHooks allow functional components to be used for non pure components. Which is a huge win IMO because the whole class/object paradigm in JavaScript is broken, and tracking what ‘this’ might be is literally impossible. I think that’s sufficient reason to use hooks. Hooks bring a completely new paradigm and I think it was brought out of Beta too early, so React now has to stick with certain concepts that appear bad ideas in hindsight (a fairly simple and relevant example would be that running useEffect on every render should not have been the default…I suspect the React team could have swapped the behaviors for empty array dependency and no dependency parameter, and it wouldn’t be any more logically weird than what we have today and the default behavior would have been far less footgun-ny). I do think the general idea behind hooks is excellent. I think some of the existing choices, however, need a significant rethink, with the additional real world experience the React devs have with it now.
- spion 4y ago> Which is a huge win IMO because the whole class/object paradigm in JavaScript is broken, and tracking what ‘this’ might be is literally impossible. I chuckled. `this` is a piece of cake to understand compared to hooks. `this` is a function argument that is typically passed to the function by placing it left of the dot at the time when you call the function. That's all you need to know - now you understand `this`. Hooks are a whole nightmare in comparison - there is a stateful counter that assigns an index to every `useState` call just to determine which result you need to get back. This is a terribly error-prone design that passed review with lots of dubious justifications.
- Waterluvian 4y agoYou can make it a linting error. There’s a lot of functions that can behave wildly different in very subtle ways. I always enjoy quizzing people on what breaks about this and why it’s not obvious: myStringNumbers.map(parseInt) Because of this I find it very smart to tool up with opinionated linting rules + TypeScript. Won’t catch everything but it covers a lot of easy mistakes that exist everywhere.
- foota 4y agoYikes, I had to look up why that doesn't work as intended. For others, map passes the value, index, and full array to a function, which is a noop for a fn of 1 argument, but parseInt takes a second argument, the radix to parse. So each iteration actually calls parseInt(value, index), which gives unexpected values.
- bigDinosaur 4y agoIMO this is a more fundamental issue with 'map'. A separate indexed map would make sense because you expect functions passed to map to take one parameter in almost all cases and usually when you need indices you should just use a loop.
- greggman3 4y agoI agree with you. I ran into that issue once. Of course I knew map takes a function that it passes value, index, array, I just forgot for a moment. It would arguably be better to have different functions for those. Very tangentially related, Apple's Metal API has a function that copies a texture. You pass it a width, height, etc... But, if the texture is compressed, then 255 of 256 possible value combos you pass it will be invalid since compressed textures can only be copied in block multiples. I think it would have been a better designed function if it only took width and height in blocks instead of pixels (with uncompressed textures defined has having 1x1 pixel blocks). Then this nonsense of 255 of 256 values being bad would disappear. There's a ton of other inconsistencies in that function. For example, you pass it destinationBytesPerRow when copying to a buffer but if the texture is compressed you pass it say 40 rows and it will only only actually copy 10 rows of blocks and only advance the destination every 4 rows instead of every row. It's arguably a poorly designed function. Thought, I suspect it was inspired by similarly poorly designed functions in other graphics APIs
- KyeRussell 4y agoDark pattern implies malice. IMO this is at worst poor forethought.
- purple_ferret 4y agoIt's a design choice to import the functionality of componentDidMount into the hooks pattern
- spion 4y agoThe original design was fine, the hooks redesign was a total miss
- satvikpendem 4y agoLots of people seem to misunderstand useEffect. It's not for transforming local state or for handling user events. In fact, there are many many reasons that people use useEffect for where it's not needed, and the recent React beta docs address this [0]. Their categories include: - Updating state based on props or state - Caching expensive calculations - Resetting all state when a prop changes - Adjusting some state when a prop changes - Sharing logic between event handlers - Sending a POST request - Chains of computations - Initializing the application - Notifying parent components about state changes - Passing data to the parent - Subscribing to an external store - Fetching data Effects should also be idempotent, they should include pure functions that don't have side effects (such as doing a POST request) which Dan Abramov of the core React team addresses [1]. [0] https://beta.reactjs.org/learn/you-might-not-need-an-effect https://beta.reactjs.org/learn/you-might-not-need-an-effect [1] https://twitter.com/dan_abramov/status/1281669881667162112 https://twitter.com/dan_abramov/status/1281669881667162112
- draw_down 4y agoAgreed, but when you have this many “don’t do what Donny Don’t does”, that may be a smell. I use React a lot and like it, but I do feel that way sometimes. I like that these docs are at least prescriptive and tell you what you should do instead.
- satvikpendem 4y agoInteresting, most of your comments are dead, I just vouched for this one. Anyway, yeah it might be a code smell if everyone is using them wrong, but I'm not sure how the React team could fix it, at least without breaking changes or moving to some other paradigm.
- dragonwriter 4y ago> Anyway, yeah it might be a code smell if everyone is using them wrong At least part of the “wrong” use is the recommended best practice has evolved over time, so following the recent recommendations would be “wrong” by the current recommendation.
- deleted 4y ago[deleted]
- WhiteBlueSkies 4y agoAbysmal framework with horrible documentation. On one hand React boasts that it's just JS but on another puts so many constraints on how you program which are nonsensical. (don't use useEffect in for loops) I have yet to see an in-depth treatise on how it works under the hood. All I get are surface level posts of guidelines and crappy posts on FreeCodeCamp written by HS students who learned how to program yesterday. State management is another nightmare as well.
- Svetlitski 4y ago> I have yet to see an in-depth treatise on how it works under the hood Check out “A Complete Guide to useEffect” [1] by Dan Abramov, one of the core React developers. [1] https://overreacted.io/a-complete-guide-to-useeffect/ https://overreacted.io/a-complete-guide-to-useeffect/
- acemarke 4y agoSee my extensive post "A (Mostly) Complete Guide to React Rendering Behavior": - https://blog.isquaredsoftware.com/2020/05/blogged-answers-a-mostly-complete-guide-to-react-rendering-behavior/ https://blog.isquaredsoftware.com/2020/05/blogged-answers-a-... as well as these other excellent posts on React's internals and implementation: - When does React render your component?: https://www.zhenghao.io/posts/react-rerender https://www.zhenghao.io/posts/react-rerender - A Complete Guide to useEffect: https://overreacted.io/a-complete-guide-to-useeffect/ https://overreacted.io/a-complete-guide-to-useeffect/ - Getting Closure on React Hooks: https://www.swyx.io/hooks/ https://www.swyx.io/hooks/ - Didact: Build a Miniature React with Hooks" https://pomb.us/build-your-own-react https://pomb.us/build-your-own-react
- LAC-Tech 4y agoReact.js is one of the leakiest abstractions I've ever seen. And the ecosystem is horrendous - it makes things slightly shorter to code at the cost of astronomical operational complexity. I tried to drink the Kool Aid, and I got paid to write it, but it's just a bad idea to build a parallel abstraction, that leaks like a sieve, that needs its own browser tools, that pretends to be reactive but really isn't. I was so much more productive when I used vanilla js, plus the odd library as needed. And if you tell me react is "just a library" - great, remove it from your dependencies and tell me what % of files you now need to fix, because I've seen multiple react projects in the wild and they all look the same.
- thrashh 4y agoWhat had always worked for me is that I write the web app as regular classes / objects, make it observable with mobx, then add React as essentially a template library — like as if it was mustache.js or something. The non-React code works on its own and is super easy to understand. You could even extract the business logic and make it a CLI or a reusable library. Shit, all my apps - Java, C++, whatever - have always been structured like this: domain logic + a decoupled frontend. I pretty much only adopt libraries that match my way. Redux did not match my way My coworkers from past jobs tell me the way I structure my projects is so clear so I think I’m on the right track
- wruza 4y agoI don’t understand why people moved away from this. It doesn’t even have to be mobx’d ideally, an informal emitter protocol would be fine, just as “rerender all reconcile the changes” mode for pages with 10k divs or less. People use a concept-heavy application framework and pretend it’s “just a thin ui library” because kilobytes. Absurdity.
- ht85 4y agoI think that arch is the best and I've used it for low interactivity projects where the frontend is almost all display. Haven't tried it for complicated SPAs with lots of DOM interaction though. Do you have any such experience? How do you architecture your models, events, processing, updating, etc? Do you have UI-less component-like pieces of code that you can compose? Or a fat root state manager that does everything? Not sure if you work on any public repos, would love to have a look if you do for inspiration :)
- rk06 4y agoCan someone explain why React can't have a more ergonomic syntax which compiles to useEffect()? Like svelte(reactivity) and vue(script setup and ref sugar) can compile their ergonomic syntax to actual apis Given the dominance of react, "switching to vue" (let alone svelte/solid) is not a viable option for many. But surely someone can shamelessly steal from them?
- ht85 4y agoOne of the great qualities of react is to not be compiled, which removes an entire layer of confusion. It's a tradeoff but it is makes it a lot more predictable.
- satvikpendem 4y agoReact is actually getting a compiler in the future for memoization: https://www.youtube.com/watch?v=lGEMwh32soc https://www.youtube.com/watch?v=lGEMwh32soc
- ht85 4y agoI had not seen that, thank you. The compilation being optional, backwards compatible, and producing readable / step-debuggable JS seems like a really nice approach.
- rk06 4y agoWTF!!? "Not to be compiled" is not a feature. It is a lack of feature. Would you say it is better for everyone to ignore typescript and use js directly?
- ht85 4y agoTS is transpiled, not compiled (at least most of it, there are exceptions like enums and certain ES features depending on target).
- spion 4y agoIt was called MobX and it was getting more and more traction before the hooks hype.
- symlinkk 4y agoThis is exhausting
- CGamesPlay 4y agoIt seems from these guides, and the comments here, that hooks are pretty confusing. For my part I learned several new things from the "you might not need an effect" doc linked elsewhere, and I consider myself to be an expert-level React developer. There is obviously something to be said against hooks being "functions, but with special requirements", and things like React safe mode actually exacerbate the problem (it used to disable console.log on the double render, leading to variables literally changing under your feet; now you just get double console logs for unexplained reasons). I'm curious if the React team experimented with an alternative set of lifecycle methods for class-based components. Like, add a new base Component class, but have the constructor freeze itself to outlaw instance variables, and require going through a useState-like API to get that functionality. What would it look like?
- ht85 4y agoI see many complaints about the react APIs. Personally, I like the way react is balanced. Yes, it can feel unintuitive or complicated to beginners, but that's because it puts a lot of emphasis on experts productivity and ergonomics while only using js, not being compiled. Once you do things the "react way" (whatever that means, you'll get there if you take time to identify and eliminate "smells"), it just feels so... smooth? You can build everything with the same methodology and flow. Simple components can feel a bit over engineered, but the hard ones ones feel much simpler than they would be in other stacks, and upgrading code and functionality feels effortless.
- deleted 4y ago[deleted]
- revskill 4y agoI just revisited reactjs docs beta website, and can't find out how to fetch data from remote server ! It's a shame.
- bobbycolley 4y agoCan you send this to the React team? I think this would be extremely helpful for the people that are learning React from random YouTube videos. I really like how you've created these visuals
- remram 4y agoI don't understand why we're still stuck with hooks. JSX was a syntax change introduced to support things that were hard to express with existing JavaScript syntax, why not do the same instead of hooks? Using function-call notation to create hooks seems like a kludge, and if you are going to process your source with an transpiler and add browser-incompatible syntax like JSX, why not do hooks the same way? This would allow us to avoid all the gotchas with non-pure functions in useEffect, breakage when calling hooks in conditions or loops (hoist them!), and whatever restrictions might come next.
- slater- 4y agoReact confusion (and the resulting pontification) has got to be one of the main things keeping the "aspiring developer" business going.