5 ms·
`setName` makes sure that state changes are queued up for the next render, allowing you to treat all state and props as constant within the current render. If y
by phailhaus 2y ago
`setName` makes sure that state changes are queued up for the next render, allowing you to treat all state and props as constant within the current render. If you are just assigning variables directly, then your state is changing within the same render cycle, which can lead to all sorts of nasty bugs that are difficult to replicate.
I get that assigning variables is easier to understand, but it's way, way harder to actually scale and maintain. Check out flux architecture.
- ww520 2y agoJust curious. How does that work on changes between depending states within a cycle? E.g. [foo, setFoo] = useState(1); [bar, setBar] = useState(); setFoo(10); setBar(foo * 2); // Is bar 2 or 20 at this point?
- aidos 2y agoIt’s 2. We’re just running a js function here with nothing magical going on. It might seem that there’s a chance that people will be confused about what bar is, but in practice all the changes are happening in handlers and bar will be a const anyway so you have no plans to mutate it directly.
- ww520 2y agoThanks for the clarification. I'm trying to understand the rationals behind React's design decision. Why state changes within the same render cycle would lead to all sorts of bugs? And why is it not a problem with other frameworks like Vue or Svelte? Just a follow up. If foo and bar are expected to be constant in the rendering code, what's the point of the setXXX() functions? Why not just make them constant explicitly and say mutating them elsewhere like in the handlers/controllers?
- phailhaus 2y agoIf you have state changes within your render cycle, then you can't write pure functions anymore, you have a stateful class. And if you have a stateful class, then React can't control when you render, because it can't know when you update a variable. So the onus is on you to decide when your component needs to re-render. This is extremely easy to screw up. You will end up in scenarios where the UI does not match the underlying state, just because the two have gone out of sync. React inverts the MVC paradigm and says "no, you don't get to decide when to render." So if you want to update state, React will manage that for you and queue up the render. With React, your UI and state literally cannot go out of sync (except for refs), and all the data dependencies are managed for you. Facebook gave a great talk on Flux architecture vs MVC ten years ago that you should check out here: https://www.youtube.com/watch?v=nYkdrAPrdcw https://www.youtube.com/watch?v=nYkdrAPrdcw > what's the point of the setXXX() functions? Why not just make them constant explicitly Look at the code again: it is explicitly constant! `const [myState, setMyState] = useState(0)`. `myState` is a const, and will literally not change its value for the entire render cycle. There is no mutable state to manage, no race conditions. You just tell React what to render based on what the value is now, and React injects the current value for you. The first time, `myState` is 0 since that's the initial value. Every subsequent render, React will give you the latest value. You can pretend everything is constant, because it is.
- ww520 2y agoI'm glad someone who's expert in React can answer these questions. I got several thoughts. First of all, I don't believe React component is pure functional with the state hooks embedded inside the component with side effects. Calling UI=F(props) twice with the same props would not produce the same result given the different sets of states embedded in them. Second, the local variable myState is const but the state is mutable; the variable myState is an alias snapshot of the state. Otherwise what's the purpose of handing out setMyState? setMyState is for mutating the state, right? It seems the need to keep myState constant is due to React's inability to detect changes to the variable to sync up the UI. It uses setXXX() to trigger the UI re-rendering. However, whether setXXX() queuing up re-rendering and causing re-rending loop is inconsequential to the programmers. It's React's implementation detail. Third, I'm interesting in learning what kind of bugs mutable state would cause in React, so that we can design better systems down the road.
- UberMouse 2y ago`bar` is 2 because `setFoo` does not update the value of `foo` until the next render
- ww520 2y agoWill bar become 20 eventually? In the next cycle perhaps? So there will be 3 cycles? 1: foo = 1, next(foo = 10) bar = undef, next(bar = 2) 2: foo = 10 bar = 2, next(bar = 20) 3: foo = 10 bar = 20 Does the above sound right?
- phailhaus 2y agoYou would not write this code for a very simple reason: all `setState` calls queue up a new render. Since you're setting the state every time the component is rendered, it will loop infinitely. Let's say you instead did the `setFoo` and `setBar` in a click handler. In that case, when you click the button it would tell React "Hey, in the next render set `foo = 10` and `bar = 2` (since `foo = 1)`. Then React goes ahead and runs your function again, and `foo` and `bar` will both be updated. The value of `foo` does not change within a render cycle, you literally don't have to worry about state.
- meowtimemania 2y agoBar is 2.
- nailer 2y ago> If you are just assigning variables directly We’re not just assigning variables directly, current JavaScript frameworks use a compiler.
- remram 2y agosetName() vs name= are just syntax. None of those have anything to do with how state changes. If you have control over the compiler (which they do) there's no reason it can't do the right thing (case in point, svelte).
- phailhaus 2y agoThis is not true at all. `setName` queues up a state change for the next render cycle, and has no effect on the current render. You cannot actually edit state directly, so that multiple handlers will all read the same state value regardless of state changes queued up for the next render. const [state, setState] = useState(0) const func = () => { console.log(state) // 0 setState(40) console.log(state) // 0 }