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 increment counter</h2>
<button type="button" onClick={()=>this.increment()}>{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
Don't reinvent the wheel. It already exists, and it's round
Work smart, not hard
Either use React's built-in state system or Redux/MobX (see 1.)
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):
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).
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.
Related
In a React class module, If counts of rendering in PureComponent are same as ones of it in Component, which one should I use? PureComponent is always faster, better than Component?
render(){
//console.log('rendered');
return(<div>...
}
Without measuring, it is hard to say.
PureComponent is nothing fancy, it justs handles shouldComponentUpdate method automatically for you.
shouldComponentUpdate(nextProps, nextState) {
return stuffChanged(this, nextProps, nextState))
}
Let's say stuffChanged is a function which does heavy computation and thus takes considerable amount of time too.
So now react will spend time in running this function (diffing) and then also in updating the DOM.
Whereas, if you did not have shouldComponentUpdate method, then your component will not have to spend time in running stuffChanged expensive function.
It will update the DOM if diffing and reconciliation of react tells it to.
So, if you just have a Component there is one diff i.e updating the DOM.
But if you have a PureComponent there is atleast one diff and sometimes two i.e diffing for state and props and then updating the DOM.
Which means PureComponent is going to be slower usually but faster occasionally.
Unless you have measured your performance of the app with some profiling tool, I would suggest you to just stick to Component.
If you wrap use PureComponent everywhere without measuring, chances are you would end up slowing your web app.
If said component doesn't have many changing parts (ie, different state or props) then pure component is a simplified way of making sure it doesn't re-render needlessly. Otherwise, use componenetDidUpdate would be a more in-depth way to handle those
I understand that we need to cleanup our components in React to prevent memory leaks (Maybe other reasons as well). I also understand how to use comonentWillUnmount (don't use anymore), and useEffect hook. However my question is what, and why (really why) do we clean up our components. I'd like a detailed answer please as I am having issues understanding this concept.
You usually don't need to at all.
For most components, simply changing state and then not rendering them will unmount them with no mess.
However, if you do anything that wont be cleaned up, you have to clean it up yourself. This means things that are outside the standard React lifecycle:
Event listeners need be un-bound (i.e. listening for onScroll of window to do something fancy when you scroll the page)
Unsubscribe from data subscriptions that were opened when that component was instantiated. (i.e. Listening for new chat room messages on an open web socket)
Cancel a timeout or interval that is no longer needed. (i.e. update a clock once per second)
This is not an exhaustive list, but the idea is that if you do anything in the lifecycle of your component that is not rendering components with some props, you should probably undo that when the component is unmounted.
Make the most of the components as dump components. display what ever the data provided as props. Make the parent componets responsible for the data fetching. This will make the components more simpler and highly readable. Otherwise no of lines of codes within the components will increase and become less readable.a less readable components is hard to understand for other developers , hard to debugg . Make unsubscribtions on unmounting the components
I've been reading and watching videos on Redux and seeing a lot of debate about managing state in components or with Redux. What I'm not seeing is anything about managing state completely outside of components with standard global variables.
For example, I could set a global state variable like this:
let state = {
player: {
username: "BillyBob",
score: 100
}
}
Then in a React component, I could have something like this:
incrementScore() {
state.player.score += 1
props.update()
}
Then in App.js, I could have this:
update() {
this.forceUpdate()
}
I realize that I'd still have to pass the update function down through the tree, but I'd at least be able to set functions at the component level and not have to worry about passing multiple pieces of state and functions to child components.
I'm new to React, but the only downside I can think of is not being able to require propTypes. Is there anything else I'm missing?
EDIT: Per request that I clarify the question, are there any major downsides to the implementation above that I should be considering that would affect even a relatively simple app?
If you look at the implementation of redux or some other state management library out there (for example mobx or mobx-state-tree), basically all of them maintain the state outside of the component as a standalone object.
However, to detect changes and trigger re-render efficiently, they implement a HOC, it's connect in redux and inject in mobx, what the HOC (higher order component) does is to wrap your component inside another component that have access to the global state, and pass the part of the state require by your component via its props. This way, the component only re-render when the data required by it changes.
Compared with these popular library approach, there are couple problems with your proposed solution.
The first is using forceUpdate, basically, the last thing you might want to do is to call forceUpdate on the root node of your app, think about scenario when someone type in an input and the whole app re-render every single keystroke.
The second will be passing an update function down to multiple level of children, it will be fine if you have only 1 or 2 nested component, but will be a big problem one your app grows. As your app grows and your state become more complex, it might not be the best idea to have a single update function to control the whole state object.
React exists to solve the problem of creating a user interface that is composed of several indepentent pieces that can be developed in parallel and can seamlessly interact with each other.
If you are going to use global namespace to define your state then you are going to bypass most of the key features of React such as:
1. Lifecycle methods
2. Virtual DOM
3. Controlled Components
4. Rendering Optimizations
In a nutshell, you are going to end up with all the overhead costs of running React while missing out on its benefits.
The 'catch' in learning a new framework or paradigm is to understand how to define the problem in such a way that it leads to path of least resistance. This can be achieved by introducing a constraint and then solving the problem within that constraint.
By favoring vanilla JavaScript for state management, you are not giving React and Redux a fair chance.
I've created a library exactly for this use case :)
Simple 💪 fast ⚡️ and small 🎈 (500 bytes) global state management for React which can be used outside of a React component too!
https://github.com/web-ridge/react-ridge-state
Stick to redux, dont complicate things for yourself :)
If I have a class with a bunch of properties, it seems like a hassle to put the properties that I modify inside (for example) this.state.myProp1 instead of this.myProp1. and then I need to make a copy of whatever property it is before I send it off to setState (because I can't mutate it directly). Like an array of objects for example.
At some point I display some of these properties so that means that I need to hold all my class properties inside this state, and then keep track of what I need to refresh, instead of refreshing the whole thing.
I almost prefer to use this.forceUpdate() instead and have my render() refer to class properties directly. Why does react "make" people use this.state and setState. Is it for performance reasons?
setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. This is the primary method you use to update the user interface in response to event handlers and server responses.
So basically setState is there to tell react when to re-render. Also setState behaves asynchronously, and updates the state only when necessary. So if you call setState multiple times immediately it will update only on the last one so as to minimize the number of re-renders and be less taxing on the browser. If there was no setState and react re-rendered every time the data changed, the browser experience would be terrible.
You don't have to use React this.state and setState if you don't want to. You can always use redux or mobx to manage the state.
Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made.
And yeah, that's why you've to make a copy of whatever property it is before I send it off to setState
IMHO, component state is an elegant concept for some special case. for example when you want to monitor the content change of a text input on live, that is, not after hit save or submit button. under such situation, a component state would be ideal place to store the temporary input and you will not get overhead to use redux action to respond on the every incomplete input. it is just like a buffer to provide performance improvement.
1. Reasons behind setState
The main reason for having to use setState is its asynchronous execution, from the react docs:
React intentionally “waits” until all components call setState() in their event handlers before starting to re-render. This boosts performance by avoiding unnecessary re-renders.
If the state object was updated synchronously it would cause consistency issues, since props are not updated until the parent component is re-rendered, so, mutating this.state directly would lead to inconsistency between props and state.
For further reference, you can check this this Github thread.
2. Reasons behind this.state
The main advantage of the state object is its immutability which couldn't be accomplished with component properties, also there is the separation of responsibility between props and state, which is way easier to handle and update individually.
Why does react "make" people use this.state and setState. Is it for performance reasons?
That's a good question - the existing answer from J. Pichardo is quite correct but I wanted to address the why in a little more depth - as opposed to what or how.
Really a better question is - why does React exist? According to this article
React’s one-way data flow makes things much simpler, more predictable, and less bug-prone. One way data flow greatly simplifies your thinking about state because no view can ever mutate the state directly. Views can only send actions up to the global state store.
Really theres a whole bunch of reasons why React has it's place as a useful UI library. But in regards to your question - uni-directional data flow - this is the main reason.
relational UIs get complex. When an app has to consume, display and update even just a modest amount of relational data and have that information displayed across multiple elements, things can get messy fast.
Using state and props the way that React does allows one to differentiate and guarantee whether a piece of the UI will just receive data to display or whether it might change it too.
If you store that data just in a random key you have no real way of knowing whether the value is changed and what changed it. By separating out your state from your component in this way, it decouples the data from the element and makes it much easier to share data between elements and also change that data in different ways.
according to this article on coupled object interfaces a tightly coupled entity is bad because:
A tightly Coupled Object is an object that needs to know about other objects and are usually highly dependent on each other's interfaces. When we change one object in a tightly coupled application often it requires changes to a number of other objects. There is no problem in a small application we can easily identify the change. But in the case of a large applications these inter-dependencies are not always known by every consumer or other developers or there is many chance of future changes.
This very much is applicable in UI development also. In my opinion this is why not setting state is going to cause you some pain later on.
React says pure render can optimize performance.
And now React has PureComponent.
Should I use React.PureComponent everywhere?
Or when to use React.PureComponent and where is the most proper postion to use React.PureComponent?
Not always. You should use it when a component could re-render even if it had the same props and state. An example of this is when a parent component had to re-render but the child component props and state didn't change. The child component could benefit from PureComponent because it really didn't need to re-render.
You shouldn't necessarily use it everywhere. It doesn't make sense for every component to implement the shallow shouldComponentUpdate(). In many cases it adds the extra lifecycle method without getting you any wins.
It can drastically save you rendering time if you have many cases where root level components update while the children do not need to do so. That being said, you will gain much more from using PureComponent in your root level nodes (i.e. PureComponent will not improve overall performance as much in leaf level components because it only saves renders from that component).
Some caveats to PureComponent are explained very well in the react docs.
React.PureComponent's shouldComponentUpdate() only shallowly compares the objects.
You could accidentally miss rendering updates if your prop changes are deep in a nested object. PureComponent is only great with simple flat objects/props or by using something like ImmutableJS to detect changes in any object with a simple comparison.
Furthermore, React.PureComponent's shouldComponentUpdate() skips prop updates for the whole component subtree. Make sure all the children components are also "pure".
PureComponent only works whenever the rendering of your component depends only on props and state. This should always be the case in react but there are some examples where you need to re-render outside of the normal react lifecycle. In order for PureComponent to work as expected (skipping the re-rendering you don't really need to happen), every descendant of your PureComponent should be 'pure' (dependent only upon props and state).
According to this reference, no (you should not use it everywhere):
(I work on React.) [...] If we recommended that PureComponent be used everywhere, it would probably be the default already. Rather -- the comparison to decide whether or not a component should be rerendered costs something, and in the case that you do want to rerender, all of the time spent checking whether you should have rerendered is wasted.
Instead, we'd suggest you be conscious of where you need to do the comparisons. It's usually only in a couple of places in your app. Good candidates are on the children of a long list or around large parts of the app that change independently (that is, cases where you know the parent should often rerender but the child shouldn't). A few well-placed shouldComponentUpdate (or PureComponent) uses can go a long way.
--
I found a tweet from Dan Abramov saying the same thing (30 Jul 2016).