10 ms·
A Visual Guide to React Mental Models: UseState, UseEffect and Lifecycles
- Etheryte 6y agoAnother day, another site that's just text and images but for some reason won't work with cookies disabled. I know not allowing arbitrary cookies on my machine en masse is my own choice, but I cannot comprehend why a page like this wouldn't work without them.
- obedm 6y agoauthor here. I wasn't aware this was an issue, sorry about that. I'll fix it
- lsalvatore 6y agoIt's cool that you fixed this, but you shouldn't apologize to this person. You published a free article on your own site. This commenter rudely criticized your site for their nontypical edge case without an ounce of respect. They are lucky to have gotten your attention at all.
- vorpalhex 6y agoThere's value in listening to your audience, and it sounds like the author didn't intend for cookies to be required to use the site. I don't think the commenter was being rude either, though it's obvious they're frustrated (understandably). You can choose to cooperate with others or fight them. Usually when we cooperate, things are improved.
- obedm 6y agoThis is my sentiment. I'd feel frustrated as well if I was on their shoes (visited an interesting article, but it didn't work because of something silly). It was also unexpected. I didn't even know localStorage could be broken by disabling cookies haha.
- seattle_spring 6y ago> though it's obvious they're frustrated (understandably) It reminds me of the meme where a guy is riding his bike, inserts a stick into his own wheel while riding, falls over (understandably), and then blames someone else for his fall.
- vorpalhex 6y agoWhen I visit a news site, to read an article, I get a video that scrolls along with me and autoplays. So I disable video autoplay. This breaks some video conferencing apps. It's a choice I have to make - some broken apps or a bunch of annoying websites. Some websites use my cookies and localstorage to track me across properties. They do this so they can harvest my profile data and habits and sell them for profit without my permission. Again, it's a choice and I think it's a fair one to make. As engineers, we don't exist to punish our users for making choices different from ours. That's a great way to end up without any users. We should make their experience as good as we can and give them value. Sometimes that isn't possible - I can't make a video conference app that's immune to blocking autoplay. That doesn't mean we shouldn't try.
- obedm 6y agoI whole-heartedly agree with this. Unless you implement a must-have feature based on localStorage or whatever, your site should still fully (or at least partially) function without it. In my case, I was aghast my blog didn't work without cookies. I don't even have ads running on it, and it's static, it should work on my grandmother's toaster!
- danlugo92 6y agoWhat do you use for cookie blocking?
- Etheryte 6y agoNothing special, I've turned off both first party and third party cookies in the browser settings. I add sites I use regularly to a domain whitelist [1], other than that I don't use much anything for cookies anymore. Historically I also used to use Privacy Badger [2], but with my current setup it isn't really all that relevant. In broader tracking and privacy context, I also use NextDNS [3] and uBlock Origin [4]. [1] chrome://settings/content/cookies?search=cookies [2] https://privacybadger.org/ https://privacybadger.org/ [3] https://nextdns.io/ https://nextdns.io/ [4] https://github.com/gorhill/uBlock https://github.com/gorhill/uBlock
- obedm 6y agoFix incoming . I'm using local storage to maintain the "dark mode" choice and it can't be accessed if cookies are blocked.
- Etheryte 6y agoThanks a lot for the quick update, really appreciate it. Works well now.
- IshKebab 6y agoYou can do dark mode purely in CSS. No need to code an explicit choice in your site.
- mikewhy 6y agoBut the point of coding the choice is ... so the user has a choice? This is a bizarre response.
- mcintyre1994 6y agoI think they mean using CSS `prefers-color-scheme` the user can set a light/dark preference at the browser level and your site doesn't have to have its own implementation. https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pref...
- satvikpendem 6y agoYes but sometimes I want a choice. For example, I use the Dark Reader extension with a pure #000 background. Many dark modes use some grey or other non-black hue, which can be quite annoying, so I usually turn them to light mode and then Dark Reader can properly convert the light theme into my preferred black theme.
- mikewhy 6y agoI'm aware of the prefers-color-scheme stuff added to browsers. AFAICT, only Firefox supports setting it at the browser level, while others will inherit from the system. This would still remove the visitors ability to say "I want THIS SITE to be in light/dark mode", without affecting all other sites / apps on their system. This page could support reading from the browser/OS, while still giving the choice on top of that. Again, this choice was probably implemented ... to give the user a choice.
- obedm 6y agoI'm the author. It's unbelievably amazing to be on spot #1 in here! Thank you to whoever uploaded it! I'm happy to answer any questions
- vorpalhex 6y agoThis is a wonderful guide and fits my internal monologue for explaining things well. Thanks for writing it!
- obedm 6y agoThank you for reading it and for your kind words! It means a lot to see this here and for people to have enjoyed it. I'll write many more such guides!
- polishdude20 6y agoHey this is really well done congrats! You should totally make one about usememo, useref, usecallback etc!
- obedm 6y agoThank you so much! That's in my pipeline. I'm going to work first on an in-depth explanation of useEffect since it's the most used one, and I'll cover all the hooks at some point. The only thing is that a lot of the same ideas are repeating themselves, but the specifics are worth explaining.
- jatins 6y agoThis is an extremely well written article. Kudos for writing it!
- obedm 6y agoThank you for your kind words! More to come :)
- w4tson 6y ago
- discreteevent 6y agoIn part 1 they talk about everything being a function including react components and closures. But I come from the "closure is a poor mans object and a function is a poor mans closure" perspective. In other words everything is an object. This is most likely because I started programming in the early 90s when first-class functions were not that common in popular languages (C had function pointers but it wasn't pretty) But either way it works fine. Everything is a first class 'thing' that has properties that can be parameterised. If the 'thing' is an object the properties are alive and can be mutated (if mutable) for the lifetime of the object. If the 'thing' is a function the properties (arguments and local vars) are alive for the duration of the call. When first class functions became mainstream though, I couldn't really understand the idea that they were fundamentally new compared to objects (in fairness this was only put forth by a few people)
- obedm 6y agoThank you for reading both articles! (author here). When I write these sometimes-overly-simplified-articles I'm terrified of explaining something wrong, or that my knowledge may be incorrect on a very specific point. I really like the way you express "everything is a first class 'thing'", I never thought of it that way.
- jlelonm 6y agoFWIW I thought they were both pretty spot on. In fact, you mentioned this about DNS: "As I read articles and tried stuff out (and broke my server config more than once) I started to grasp the system, to get glimpses into how it all worked, until eventually it “clicked” and I felt comfortable working with it." Have you written about your mental models for DNS? Color me interested!
- obedm 6y agoThat's something I hadn't considered before. That's probably something that a lot of people would find valuable. Out of all the questions my students ask me, there's always confusion about the way servers talk to each other, or what they even are. I'll definitely write about this now haha. Thank you for the idea :)
- devit 6y agoWhile equivalent to a proper approach, it feels like hooks are an unnecessary hack. What could be done is to have the component function return a closure that returns the VDOM nodes instead of the VDOM nodes themselves, and then the hooks would be run only once, since rerendering would only run the returned closure and not the whole component function, and there would be no need for the magic or rules. Like this: const Component = component((comp) => { const [show, setShow] = useState(comp, false); return (...props) => ( <div> <button onClick={() => setShow(!show())}>Show Menu</button> // Mounted with show = true and unomunted with show = false {show() && <MenuDropdown />} </div> ); }); Where the changes are that the hook takes the component as an argument, show is now a function rather than a value and a closure (that takes the props) is returned rather than returning the VDOM nodes directly. The React Hooks API is essentially equivalent to this, but inelegant, unintuitive and somewhat inefficient.
- jcelerier 6y ago> What could be done is to have the component function return a closure that returns the VDOM nodes instead of the VDOM nodes themselves, and then the hooks would be run only once, since rerendering would only run the returned closure and not the whole component function, and there would be no need for the magic or rules. what could be done is actually using a proper reactive language where things look like this, instead of hacking HTML, JS and whatnot in an unholy mess of syntax: Button { text: "Show menu" onClicked: menu.visible = !menu.visible } Menu { id: menu } e.g. a bit like this: https://tinyurl.com/yaawdomh https://tinyurl.com/yaawdomh
- earthboundkid 6y agoYou may be interested in https://crank.js.org/blog/introducing-crank https://crank.js.org/blog/introducing-crank which essentially works as you propose.
- spankalee 6y agoWhat's the benefit of this over class syntax? If we had decorators in the language already we could make field reactive: class Component extends React.Component { @state show; render() { return <div> <button onClick={() => this.show = !this.show}>Show Menu</button> // Mounted with show = true and unomunted with show = false {this.show && <MenuDropdown />} </div> } } Hiding the underlying stateful objects that back React components seems like it causes more confusion and complicated APIs than it's worth. Likewise closures returning closures and state defined with function calls seems like re-inventing classes. Just make the component itself stateful and the lifecycle explicit and it's all so much simpler. Then attack the problem of composing JS classes from pieces with tools available to all JS classes, not just the framework at hand.
- pier25 6y agoI haven't used React since before hooks were introduced but I switched to Svelte a couple of months ago and now I find the cognitive load of using React totally unnecessary. Even more now with hooks. In Svelte you never think about these or other considerations (eg: useMemo). Just update some state and that's it. Svelte will render consistently faster than React, with less code to write (and maintain). It's true with React you get a bit more flexibility but I have yet to find a situation that cannot be solved with Svelte.
- untog 6y agoI have to agree. I still haven’t used hooks yet and I’m sure I’ll get used to them when I do, but by comparison to this article Svelte is a breath of fresh air. It’s simple, it works. A lot of people object to it because it’s very different to React, but judging by the diagrams in the mental models here I don’t think that’s any bad thing. An aside, and I know complaints about hooks are very boring now, but I remember when React first arrived on the scene. The API was a delight. shouldComponentUpdate, willReceiveProps, etc. Everything was so clear from the first second you picked it up. Now? I’m less sure.
- superhawk610 6y agoTo say that you never have to think about those considerations in Svelte is pretty unfair - reactive declarations/statements are functionally equivalent to hooks, and they also carry a somewhat nonintuitive cognitive load until you've begun to "think in reactivity". It's also worth considering that hooks, while unintuitive in function, do use intuitive, non-magical syntax (unlike Svelte's reactive syntax). FWIW I like both, I just think they're both equally unintuitive until you make the mental connection.
- pier25 6y agoI guess we're all different, but I've never had to think much about reactivity in Svelte. Most of it can be explained in a HN comment: Component state just does its thing. You change it with = and the component is re-rendered. Writable stores need to trigger changes with set() and you need to use $ whenever you reference it in a .svelte file so that Svelte handles subscription automatically. Reactive statements $: are a bit more complex. Every variable inside those is referenced by the compiler so that it knows when you are mutating it. Either with = or if it's a writable store with set().
- konaraddi 6y agoI think a correction needs to be made in Part 2 "How Does State Change"[0]. The author says "Long story short, don’t expect state to be updated right away" in the context of using `searchValue` right after calling `setSearchValue`. This gives the reader the impression that state is sometimes updated right away and sometimes not so we can't depend on it. However, it's impossible for a useState variable (e.g. `searchValue`) to be updated without a re-render [1]. Thus, using `searchValue` immediately after `setSearchValue` will always be outdated. So state is only updated after render. [0] https://obedparla.com/code/a-visual-guide-to-react-mental-models-part-2-use-state-use-effect-and-lifecycles/#how-does-state-change https://obedparla.com/code/a-visual-guide-to-react-mental-mo... [1] The `setSearchValue` updates a value that's outside (and captured) by the closure, React will re-render the component since setSearchValue was called (idk how this works behind the scenes and i think rendering is async), during the re-render `searchValue` and `setSearchValue` are assigned values again, and thus `searchValue` will finally be the updated value.
- obedm 6y agoYou're right, the code is not explained clearly enough. I intended it to be a "don't do this!" part, but I didn't really explain that. Great attention to detail, thank you for pointing it out, I'll update it!
- iooi 6y ago> In short, a closure is like a semi-permeable box, letting information from the outside get in but never leaking anything out. This is just wrong. For example: const counter = () => { let count = 1; return () => count++ }
- uryga 6y agothe counter's value isn't leaking out, you're explicitly returning it. that's the point – the only thing you can "get out of" a closure is what it returns when you call it (see also: the JS pattern of using closures to create objects with truly private "fields")
- NegativeLatency 6y agoYou could mutate some shared/global state from inside a closure as a way of getting information/state out
- obedm 6y ago(author here) this is true! That's what I'm trying to explain in the `state` section of the article. State lives in a "global" and the component is modifying it. So it's "leaking info out". It's hard to make comprehensive mental models that cover all the bases and leaves nothing out
- uryga 6y agoi considered adding "mutate a global" in there but didn't feel like that was relevant to @iooi's comment. maybe i should've quantified "the only thing" a bit more :)
- _hilro 6y agoI find the images very off-putting and unclear. https://obedparla.com/static/1c6caf6685f0bd3381d84a8166579de1/83d9f/react-rendering-mental-model-from-part1-cleaner.webp https://obedparla.com/static/1c6caf6685f0bd3381d84a8166579de... What's with the wavy lines as representation? Similarly for an image titled 'Javascript closures visualized', we get https://obedparla.com/static/e0caedb67992235db77271808958da3d/e922d/javascript-closure-mental-model.webp https://obedparla.com/static/e0caedb67992235db77271808958da3...
- wjmao88 6y ago> React state is scoped to the outer-most box, that way it doesn't change on every render The state (of the hooks) for individual components are still scoped to that component only, its just stored in the "outer-most box", and the structure corresponds to the component tree. If a component unmounts and remounts, the prior state is lost.
- obedm 6y agoYou're correct, this is something I tried to convey in my article but I didn't want to spend too many words on it. When retrospecting about it, I realized I didn't think of it this way, even though it's correct. My mental model is like "state is just kept, don't worry about it". Thank you for pointing it out though, it's hard to be accurate and succinct