The React-Redux project I am working on handles a group of participants currently organized in a JavaScript object like a map with key:value pair defined as participantId:participant.
I am receiving updates in terms of individual participants, so the program should have exact knowledge of what to re-render.
The components are currently setup such that the parent component is connected to the Redux state, and the participants object is converted into an array and passed down to its children's props.
Every time the update action passes through the reducer, it generates a new state, which fails mapStateToProp's shallow comparison checks and triggers a re-render of the parent component and child components.
Re-rendering the entire list of child components negates the purpose of receiving updates for one participant at a time. If possible, I would like to re-render only the specific child component that has updated and re-render the entire list only when a child is added/removed.
Can I do this with React-Redux? Especially when I'm storing the participants as a mutable data when Redux encourages me not to? Or should I be looking into using ShouldComponentUpdate and ditch Redux?
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 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.
I have a list of observable objects:
[
{
key1: "x",
updateTs: "y"
},
...
]
The user can mutate these objects through the UI.
Those changes are sent to a remote server, and once the request returns the "updateTs" is updated.
The issue is that when online, this causes a double render:
Initial edit from UI.
When remote request returns and edits updateTs.
I am not using updateTs in my view, only its sibling keys
(key1).
MobX #observer tracks reads to objects, so it triggers a re-render.
This causes UI jank as it consumes JS CPU time to re-compute the virtual dom and diff it (the list is very large).
Is it possible to avoid the second re-render?
In order to avoid the "jank", make your Mobx components as small as possible. For example, create your "item" component with a "key" subcomponent and a "ts" subcomponent (and make both subcomponents observers). Mobx then should only cause the subcomponents to update, and because each subcomponent only cares about one property, editing one should not affect the other.
You will have to pass the entire "item" observable to the component (as a prop), though, so that Mobx can track it properly. Also, make sure that updates to the item collection and values are in place, and don't re-create objects.
You are correct that reading a property causes Mobx to track that property's changes. Therefore, if you do not want a component to re-render, then you must not change anything you read from in that component. However, subcomponents that are observers track Mobx properties in separate contexts. So if you read something in a child observer component but not in the parent component, then Mobx won't update the parent.
See also: Optimizing Mobx for React
I guess you can find answer here component lifecycle
Choose one of variant that fits you:
1. uses shouldcomponentupdate
2. uses PureComponent
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 am thinking of creating a list components which receive list of items and then return a list of <li></li>. Moreover, the list can be appended dynamically via ajax call.
I would like to ask in this situation, where should I store the data, props or state?
In most cases: use state for data that changes over time.
A common way of doing this is to have two components, List and ListItem. The List component should handle the state, ajax calls and the transfer of list content as props to the child component ListItem.
<List>
<ListItem>
<ListItem>
<ListItem>
...
</List>
So List stores the data as state. And ListItem is stateless and just receive its data from List.
React docs: What Components Should Have State?
Most of your components should simply take some data from props and render it. However, sometimes you need to respond to user input, a server request or the passage of time. For this you use state.
Try to keep as many of your components as possible stateless. By doing this you'll isolate the state to its most logical place and minimize redundancy, making it easier to reason about your application.
A common pattern is to create several stateless components that just render data, and have a stateful component above them in the hierarchy that passes its state to its children via props. The stateful component encapsulates all of the interaction logic, while the stateless components take care of rendering data in a declarative way.
Maybe this helps to understand the structure of building react apps: Tutorial: Thinking in React