This question is about internals for partial re-renderings with React-Redux.
To explain what I mean, I will first introduce a very crude technique for managing state without any state management libary.
The technique uses a a huge "AppState"-object that is owned by the top-level App-component.
Suppose that this AppState holds not only state-properties, but also several callbacks that mutate those state-properties.
Furthermore, suppose that we use props to pass down this AppState throughout the entire component hierarchy.
Thanks to the ES6-spread syntax, passing a huge number of props can be done without a lot of boilerplate code.
In the top-level App-component, it will look like this:
<ChildComponent {...this.state} />
In all other components, it will look like this:
<GrandChildComponent {...this.props} />
It is important to note that the ES6-spread syntax does not actually pass the AppState-object. Instead, it extracts all the AppState-properties and passes them as separate props.
Now we should distinguish between top-level properties and nested child-properties of the AppState:
If I mutate a top-level property of this AppState by calling setState, then the entire app will re-render (unless I use things like pure components).
However, if I change a nested child-property of this AppState, then nothing will happen because React does not notice the property change.
This leads to my final questions:
What is the render-performance of this crude approach in comparison to Redux?
How exactly does Redux handle "partial renderings", such that only some of the Components re-render after a state mutation?
If I mutate a top-level property of this AppState by calling setState, then the entire app will re-render (because everything depends on the AppState).
If you mutate and use pure components then nothing will render, you change state by creating a new state object.
However, if I mutate a nested child-property of this AppState, then nothing will happen because React does not notice the property change.
This is only true if you mutate and components are pure.
What is the render-performance of this crude approach in comparison to Redux?
Prop drilling will re render the entire tree but branches that use state that didn't change won't re render if they are pure. Prop drilling is bad for maintenance because if you need to refactor grand child state logic you may need to refactor the whole tree or branch. But from a performance point it would not take a big hit provided that you use pure components and are careful when passing callbacks and not re creating them on every render (see useCallback).
How exactly does Redux handle "partial renderings", such that only some of the Components re-render after a state mutation?
React-redux useSelector or connect mapStateToProps are always called every time dispatch changed state and before rendering.
If the result is different than last result then react-redux will trigger render of the component. If the component gets props then a render could also be triggered because props change and mapstate/selector will be executed.
A connected component will observe state and render when the result of mapState or selector has changed. An example app with logs showing what react-redux will execute can be found here
For state management, you don't necessarily have to use Redux, if your use cases are small, maybe React Hook would be perfect for you.
For React rerendering matter, what I know is there are several strategies (useMemo, PureComponents) provided by React for managing and improve the performance. It really depends on how you manage your components.
One example is using PureComponent, even if you have a large state in your top-level app.js, if you manage the child components properly, they will not re-render if their receiving props haven't changed.
Related
I know using "key" prop on any React component will re-mounts if there is a change in key value.
Using "ComponentShouldUpdate" lifecycle method will just update the component instead of re-render.
In what cases we should use "key" vs "ComponentShouldUpdate"? Does using one provides advantage over other ?
I think you should revisit the documentation because what you know is not correct.
a component gets updated when props or state change no matter if you have keys or not in the component
shouldComponentUpdate gets executed every time before render and tells if the component should be re-rendered or not. for regular components the method just returns true. you can overwrite it. pure components do a shallow check.
keys only help react know what changed during a render/re-render. they don't stop/prohibit a re-render.
You should use shouldComponentUpdate as a optimization.
key and componentDidUpdate are used for entirely difference purposes.
From the docs,
React implements a heuristic O(n) algorithm based on two assumptions:
Two elements of different types will produce different trees.
The developer can hint at which child elements may be stable across
different renders with a key prop.
What this means is that if a key passed to a react component changes, react will tear down the old tree represented by the component at DOM and create a new tree(unmount and then remount the component even if nothing has changed except the key).
On the other hand, componentDidUpdate will run after a component has been updated i.e a prop or state for the specific component has changed. Update will not result in the teardown of the tree from the state.
You should not be using key in usual cases and let props/state changes trigger componendDidUpdate and handle your logic there. Key is used on some occassions where you have a large amount of state logic and you want to reset your state logic to initial state i.e remount your component from scratch. Essentially, you should avoid using key to unmount and remount your component as this operation affects performance.
This has come about because during prototyping, I'm finding that incoming new prop(s) might be an array of complex objects, so prevProps.myProp===this.props.myProp is always false. JSON.stringifying them both before comparison works, but feels unreliable.
I'm trying to write a reusable function for Class Components that compares prev/new props in react's componentDidUpdate. For example:
componentDidUpdate(prevProps) {
// First, get difference here, possibly using a lib like npm 'deep-object-diff'.
// ...or just JSON.stringify both and do string comparison
const changes = getTheDifference(prevProps, this.props)
// Don't do anything if there's no changes.
if (!changes) return
// Then I want to do something like:
this.setState( Object.assign(this.state, changes) )
}
...that would mean any time the incoming props change, those get immediately reflected in state. I'm having some issues finding a suitable diff lib, but I still feel like I shouldn't be having to do this and am missing something - is there a generally accepted "normal" way to do this, or is me having this problem just a sign of:
The component is trying to do too much/state too complex?
I should be mapping props to state with something like Redux? (trying to avoid this until absolutely necessary)
I'm overthinking it, sometimes the logic in a component's componentDidUpdate is just complex and unique?
that would mean any time the incoming props change, those get immediately reflected in state
Yes, that's wrong. When I first started out I was doing the same thing.
state is something "owned" by that component (noteworthy: not all components need state at all!).
props are something that are "owned" by a higher component.
Best example:
ComponentA passed an id to ComponentB as a prop. ComponentB uses that id to make an API request (for example).
The status/results of that API request form part of ComponentB's state (it's "owned" by your component). The id passed in as a prop is NOT part of ComponentB's state (it's owned by ComponentA, or maybe somewhere higher in the tree that passed it as a prop to ComponentA).
When the id prop changes, ComponentB will need to make another API request.
EDIT:
The complexity of lifecycle methods is why React has highly encouraged functional components.
You should think of components as functions. It's a lot easier to write the logic if you just think of it as input -> output.
componentDidUpdate has been moved to useEffect with a dependency list so you can say - run this function, but only when this prop changes - which is a nice way to break down massive componentDidUpdate methods into tiny readbale/testable chunks.
I've heard a lot of people say hooks ruined react, but I highly disagree with them. React saw the problems people were running into in the community by misusing class/instance based components and instead of lecturing about how to use them correctly, they nudged people to writing better components by introucing a simpler API - functions, while they still can and will be abused - are generally simpler to deal with than classes and align nicely with composition over inheritance and declarative over imperative.
After a lot of search and working with React and React Native. I still have a pretty vague opinion on which
is best to use and in what situations
Having the parent component be connected to the store and passing as props all data to children functional components. This what I initial though was the "React" way but pretty soon I saw that as the app grow the amount of logic handled by this parent component starting too be to big and messy.Also child components start to have children of its own and so on and so forth.
Having parent component (Screen for example) that is functional and each child that needs information from the store will be connected to it. This is much more "clean" solution but will create a lot of store connection "duplications" which are not necessary.
Using Redux store
My question in general which is more recommended pattern to use and in which use cases, also would be nice to know what is the price for having a lot of connected (containers) components
Not sure i can provide a right or wrong answer for this question as each has its pros and cons.
My rule of thumb is to connect deeply nested components only when their parents are "proxies of props". That is they accepts props only to pass them down to their children.
If i may quote (myself) from this answer:
Avoid connecting components when you can and pass down the props to
the children, the main reason for this is to prevent dependency on
redux. I prefer keep my components "dumb" as i can and let them
concern only on how things should look. I do have some components that
concern on how things should work and these components are mainly
dealing with logic and passing down data to the children, they are the
components i often connect.
When i notice that my app is scaling and some of my components are
acting as a proxy of props (i even got a word for that! "Propxy"),
that is they get props from their parent and pass them down without
using them, i usually inject a connected component in the middle of
the components tree so i can let the "propxy" components down the tree
flow be more lighten and slim
You should also note that one more pitfall with connected components is that each render will trigger the mapstateToProps method. if you got some heavy logic there you should memoize it, usually done with reselect
As for the benefit of connecting a component, well you probably realize that already. you get quick access to the Provider's state via react's context.
Edit
As a followup to your comment:
about the rendering - wont I have much more unnecessary rendering if Ill have a deep nested children (common in medium to large apps) that will be unnecessarily re rendered on each parent update
Well the connect HOC wrapper won't trigger a re-render if the previous object of mapStateToProps is the same as the current object returned. so no unnecessary re-renders to your connected component will take place.
You can read in more details on how it works and how the logic was evolved over time in this article
I use the first option.
The cons you wrote are correct, but i think its easier to debug and understand the data flow this way.
Don't connect a component to redux if the current component doesn't use this data from redux and only passes.
If the component uses data then connect to redux.
If the current component uses data from redux and the next component also uses it then you can pass and don't need to connect the next component to redux.
MAIN RULE:
if there is a gap in the data usage chain from parent to child then don't need to pass data from parent to child
connect(parent) (don't use props) => child (don't use) => child (don't use) => child (using) - better to connect last child. Isuue related to props dreeling
I'm working on a React + Redux project with a couple of other developers and we can't agree on what the best practice is regarding where to pass in the state and the actions.
My approach is to have a 'container' or 'provider' component, which is the parent component, all required states and actions are mapped to state and passed down into child components, creating a single source of truth. However the down side to that is, you have to remember to pass actions and values down through each child component, which can be tricky to follow.
Another developers approach is to use the mapStateToProps on each component where it is needed, at any point in the stack. So if a child component three or four levels down requires a certain state, he would use mapStateToProps on that component. He would also import action creators directly using the import keyword, instead of calling them as props. I don't like this approach because you're potentially injecting states multiple times and you can't switch out your state or actions quickly in one place.
I can see both approaches have their merits and fallbacks, so I just wondered if there was a definite best practice as to where and when to inject state/actions into a stack of React components.
I worked on a relatively large Redux codebase and the approach we chose and which I like was your second approach using mapStateToProps on containers component which dispatch actions and delegate rendering to dumb components.
You want to be able to reuse them in many places without having to pass down a state. Your top redux state is still the source of truth but mapStateToProps will allow you to access only the part of the state which you need within this container.
Redux documentation is amazingly well done, check it out, it recommends container components implementing mapStateToProps http://redux.js.org/docs/basics/UsageWithReact.html
It's up to you how many components you connect to Redux, but generally speaking having more connected components is better for performance. For more information, see the Redux FAQ on connecting multiple components, as well as my blog post Practical Redux, Part 6: Connected Lists, Forms, and Performance.
I'm fairly new to React and I'm trying to understand a clean way for child components to communicate with each other.
In a simple component, I know that I can make use of props to pass data to child and callbacks for children to pass data back to parent component.
In a slightly more complex case, when I have multiple children components in a parent component, the communication between the children gets a little confusing. I'm not sure what I should do for children components of the same level to communicate with each other.
In my case, I decided that, maybe, I could use states. So I will have a state value in the parent component, and pass it on the children's props. Similarly, the callback handlers (called from the children component) in the parent component will help to set the states accordingly so that a state value gets passed on from one child to another through React's binding.
And a pseudo code could look something like:
//Inside Parent Component
constructor() {
//initialise state for the child components
this.setState({testList: []});
}
render() {
return (
<div>
<ChildA onSomething={this.onSomethingHandler} testList={this.state.testList} />
<ChildB onSomethingElse={this.onSomethingElseHandler} testList={this.state.testList} />
</div>
);
}
onSomethingHandler(evt):void {
if(blah.blah.blah) this.setState({testList: this.state.testList.splice().push(evt.value)};
}
onSomethingElseHandler(evt):void {
//Some other complex biz logic...
if(blah.blah.blah) this.setState({testList: this.state.testList.splice().push(somethingOtherStuffDueToLogic)};
}
//Inside ChildA Component
export IChildAProps {
onSomething: (evt)=>void
}
render() {
//Do some logic from the value in testList property
if(this.state.testList == blah blah)...
return (
<button onClick={this.props.onSomething({id:321, value:"wassup! I'm ChildA."})}>ChildA</button>
)
}
//Inside ChildB Component
export IChildBProps {
onSomethingElse: (evt)=>void
}
render() {
//Do some logic from the value in testList property
if(this.state.testList == blah blah)...
return (
<button onClick={this.props.onSomething({id:123, value:"yo! I'm ChildB."})}>ChildB</button>
)
}
At this point, I'm starting to wonder if the logic in that 2 handler methods, namely onSomethingHandler() and onSomethingElseHandler() in the Parent component, should actually be resided inside the child components themselves? I thought of this because those logic look like something the child component should be handling on their own to serve their purpose. The parent component shouldn't do it for them or it might just grow messy. But I've no choice because of how I'm handling their communication. Apart from this, I also created a new state simply just to allow them to communicate.
So far, this is still relatively manageable. But in my own experiment, it has got to a stage where I've children component nested inside another children components that need to communicate across other children components of the same (or sometimes different) level. Using states for communication also meant that I have many states all over the place, which doesn't look like a good idea to me. And the parent components ended up with tons of messy callback handler methods to manage all that propagation of data up and down the component tree.
The situation is so messy that I can at most illustrate it as something like so:
And you can see in the above illustration, ChildB ended up having yet another state just to help passing that information between its children components.
I'm sure I'm missing something that I should know about React. The callbacks I'm having in the parent components seem a little too much just to handle data propagation. How should I really organise the communication of children components in a clean and maintainable way?
Every React programmer hits this wall at some point in time. I did too. The answer is to use Redux for state management. You have experienced how tedious it is to use React's native state.
Redux is a state management mechanism which can be used in conjunction with React. So you won't be using React's state, instead you will use Redux.
Redux provides a single store, where the state of entire application is stored. You can access the state in your components using connect() method.
But there is a caveat. Not all of the react components are connected to the Redux store. There are two types of components-
Smart/connected components: Connected to redux store
Dumb components: Dependent on connected components
The idea is to pass the state from redux store to Connected components via React's props. The connected components can directly consume state from the store. The dumb components are not directly connected to the redux store. The connected components also pass the state to the dumb components via props. So you see, React's state is bypassed altogether. Now, if you want to change the state, following events must happen-
An event is fired from the smart/dumb component.
Actions are dispatched to the store
Reducers create a new state according to the actions.
A new state will be stored in the store.
Store will return new state to the connected components via connect() through props
Dumb components will receive new state from connected components through props
What are actions and reducers?
Actions are nothing but javascript objects that describe how to change the state.
Reducer is a "pure" function which builds and returns the new state tree according to the action dispatched to the store.
Redux - http://redux.js.org/
Redux-thunk - https://github.com/gaearon/redux-thunk
Redux-saga - https://github.com/yelouafi/redux-saga
Most fashion way is using Redux.js (or flux.js) to matain your child components state.
http://redux.js.org/
If you don't like invoke third party js. You can use refs property:
https://facebook.github.io/react/docs/more-about-refs.html
We can use the react context API,
Context provides a way to pass data through the component tree without having to pass props down manually at every level
Also, note that Mark Erikson has mentioned in his blog,
Yes, the new context API is going to be great for passing down data to deeply nested components - that's exactly what it was designed for.
If you're only using Redux to avoid passing down props, context could replace Redux - but then you probably didn't need Redux in the first place.
Context also doesn't give you anything like the Redux DevTools, the ability to trace your state updates, middleware to add centralized application logic, and other powerful capabilities that Redux enables.
To handle scenarios you mentioned, context API is a good option and you don't have to use additional libraries for that.