简体   繁体   中英

Why to store data in state in react

I want to understand what we lose if we don't store the data in state . We can still trigger re-render by using this.setState({}) . Please provide in-depth analysis.

Note that I am not concerned to maintain the state of application(usually done via Redux, Mobx etc.)

 class App extends React.Component { constructor() { super(); // this.state = { counter: 0 };//Am I loosing something by not doing in this way } counter = 0; increment() { this.counter++; this.setState({});//trigger re-render as new object is set to state // this.state.counter++; // this.setState(this.state); } render() { return ( <div> <h2>Click button to increament counter</h2> <button type="button" onClick={()=>this.increament()}>{this.counter}</button> </div> ); } } //export default App; ReactDOM.render( <App />, document.body ); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> 

One of the biggest things you'd lose are lifecycle methods and maintainability. The whole idea behind React's state is to make it easier to keep data in sync both in that component and in any child components being passed data from that state, but for all that to work as intended, you need to update the state using this.setState() and read from it through this.state .

What React does when calling this.setState() (besides updating the state) is go through the necessary lifecycle steps as well. One of the main things it does then is re-render the component (and it's children), but as you said, you can trigger that using this.setState({}) which to some extent is true, but only if you're also okay with losing:

Performance

JavaScript is fast. React is fast. What do you get when you cross fast with fast? I don't know, but it's probably something really fast. Especially if you like using React's PureComponent , which is exactly the same as Component with the difference that PureComponent implements shouldComponentUpdate using shallow state and props comparison, whereas Component doesn't. What this means is that if you don't update anything (state and props both stay the same), the PureComponent won't re-render the component, whereas Component will. If you don't use React's state system, you can't really use PureComponent for better performance, nor can you implement shouldComponentUpdate , since you can't compare your old data with your new data. You'd have to re-implement that performance feature yourself.

Stability

Saying goodbye to React's state system in favor of a hacky solution also means saying goodbye to application stability, and saying hello to more problems down the road than you can count. Let's take the performance problems from the above point, and let's put them to scale. In order for you to have a more performant application, you'd have to either repeat the above for the whole application, or create a generic solution that you could re-use across components. Not to mention the fact that remembering to call this.setState({}) every time you update the data, just to make the component re-render. Forget it once, and your application will start to display inconsistent data, because even though "your state" updated, React's state hasn't. Scale that up, and you've got a problem.

Colleagues that don't want to hurt you

Let's face it. You're probably either new to programming, new to React, or haven't worked in a team, and that's okay, we all start from somewhere. What's really important, though, is not making your team want to hurt you so bad you'd have to pick a new specialty. One that doesn't require fingers and/or eyes. The benefit of using tried and tested frameworks, as well as using them correctly, is that there's less hassle for everybody. Nobody has to create and maintain hacky solutions to already existing use cases. Nobody has to tear their hair out due to inconsistent rendering. Nobody has to lose an eye or break any fingers because somebody thought it'd be a good idea to reinvent the wheel, but this time as a cube.

TL;DR & Final words

  1. Don't reinvent the wheel. It already exists, and it's round
  2. Work smart, not hard
  3. Either use React's built-in state system or Redux/MobX (see 1.)
  4. Use this.setState for updating, this.state for reading. Don't directly mutate state , as React won't call any lifecycle methods, resulting in unexpected behavior and bugs

Setting component state on a component instance can lead to buggy component and have an impact on maintability of the component.

Correctness of Component state isn't guaranteed

If you generate clicks faster than this.counter is incremented, the computed counter isn't guaranteed to be correct .

setState guarantees that multiple calls to it are batched together to be applied. For this reason, counter value is guaranteed.

this.setState(prevState => ({counter: prevState.counter + 1}))

No separation of rendering logic from state mutation

Also, in use cases where you have to avoid a render when the component state didn't change, React.Component lifecycle methods like shouldComponentUpdate captures the next state _effectively separating the decision to render from update to state.

Keeping state on the component instance will have you computing the next state, comparing it to the previous one and deciding whether to force a rerender. This can become difficult to maintain if you have more state to manage for the component.

One specific thing I can think of is that state and props are big things in react.

For instance, when you call .setState it isn't exactly a trigger to update ui but rather a queued update request.

Why does it matter? Several reasons ( and more here ):

  1. A setState doesn't necessarily mean that the component will indeed re-render. if the state is left the same as before, react will notice, and will skip the render cycle which gives you a performance boost (and is one of the key advantages on top of the virtual DOM).
  2. setState is async (usually), and several setState can happen before a single render. thus, setState({a:true});setState({a:false}); can in theory just skip the intermediate render (performance boost again).

One other thing is the idea that there is only one source of truth to a react component.

This is a design principal that allows easier development and debugging as it helps with code readability. React is just a View framework (as in MVC / MV*, just without the M). It is up to you to do the rest. Since it is just a View, Components are essentially just HTML (or rather, JSX) representation (or bindings, depending on lexicon) of plain data. That data is state , and therefor has a special status. It makes it much easier to think of (and code) React, with the understanding the Components are just (state) => { <html>} functions. when you want to see where the state changes, you just look for setState . as simple as that. you could of course store other things as class members, but that would defeat the purpose of simplicity and readability.

*PS: the above also means that time-travel is easy. you just play the state changes backwards (in theory) which is also a cool benefit of keeping things simple.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM