5 ms·
I'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 wi
by ww520 2y ago
I'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.
- phailhaus 2y ago> Calling UI=F(props) twice with the same props would not produce the same result given the different sets of states embedded in them. Correct, but you as the component writer don't care. From your perspective, you are writing a purely functional component because you have no control over the injected state. So your function is "pure" with respect to the props that are passed in and the state that is injected by React. It's actually UI = F(props, state) React can (and will) run your component function multiple times with different values before rendering, so it is extremely important that you have no actual side effects. Otherwise, these "intermediate renders" will affect the final render, which breaks the contract that your function return the same values for the same inputs. > the local variable myState is const but the state is mutable It is "mutable" in the sense that it changes between invocations of your function. But no, it is immutable within a single render of your function. The fact that you can treat all state as constant is one of the massive advantages of using React. You literally don't have to think about state mutating within a render cycle. You just write a function that spits out JSX given props and state. > Third, I'm interesting in learning what kind of bugs mutable state would cause in React You're going to run into issues where: * the order that your function is called somehow affects the final render. Now you need to worry about how your function is called, and with what values. Not an issue with React. * the underlying state is out of sync with the UI, because you changed it but didn't trigger a re-render. Not possible in React (except for refs). * the internal state of the component ends up in an invalid state because of the ordering of set-state calls and renders. Again, not possible in React because all set-states are batched together and applied consistently to the next render cycle. There's no such thing as a "partial render".
- ww520 2y ago> Correct, but you as the component writer don't care. From your perspective, you are writing a purely functional component because you have no control over the injected state. So your function is "pure" with respect to the props that are passed in and the state that is injected by React. It's actually UI = F(props, state) This is like calling the constructor of an OO class a pure function. The class constructor takes in parameters (props) and the created instances don't interfere with each other's states. With all due respect, this stretching of the definition of pure function is beyond recognition. > * the order that your function is called somehow affects the final render. Now you need to worry about how your function is called, and with what values. Not an issue with React. The order of the function invocations calling setXX() matters anyway in React or non-React libraries. The queued up setXX() calls pending state updates in React has an order. There's no difference in handling state update ordering between React and others. > * the underlying state is out of sync with the UI, because you changed it but didn't trigger a re-render. Not possible in React (except for refs). > * the internal state of the component ends up in an invalid state because of the ordering of set-state calls and renders. Again, not possible in React because all set-states are batched together and applied consistently to the next render cycle. There's no such thing as a "partial render". Both of these are because React's inability to detect changes to state updates in a comprehensive and fine grained way.
- phailhaus 2y ago> This is like calling the constructor of an OO class a pure function. No, because again I must stress that you cannot control the injected state. You merely ask React to set state in the next render. The next call to your function may not have the new state! React can and will call your component function multiple times with different values of state, so you must assume it could be anything. This is why component functions must be written without any side effects, because there is no way for you to know which invocation React will actually persist to the DOM. For this reason, you really are writing a pure function with respect to props and state. It's a requirement in React! > There's no difference in handling state update ordering between React and others. The huge difference is that because state is fixed within a render cycle, it is not possible to read an intermediate value. You can't get in a situation where one handler updates a state value, and another (or the same) handler reads that new value within the same render cycle. That's the sort of order-dependent nonsense that can make a component very buggy and fall into an inconsistent state. > Both of these are because React's inability to detect changes to state updates in a comprehensive and fine grained way. That's because React is built in a way to provide a set of very specific guarantees when it comes to managing state and rendering it. You are free to come up with "simpler" solutions, but you are going to have to sacrifice some of these guarantees for that simplicity. React component functions have no side effects, and are defined completely declaratively. That is extremely powerful with a lot of advantages, such as being trivially composable. It is extremely easy to extract functionality out of a component and turn it into a reusable hook, because everything is already stateless. If you ditch all that just so you can use variables, you lose all of those benefits. You'll have to deal with truly stateful components, ones that are path dependent and difficult to reproduce for debugging. By contrast, you can reproduce any React component's UI by passing in the same props and state. This is only possible because state is external to the component and out of your control.