react js - key vs componentshouldupdate - javascript

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.

Related

React-Redux vs shouldComponentUpdate Rendering Optimization

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?

Normal/Standard way to compare prevProps in componentDidUpdate

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.

Debug react component rerender

I'm trying to debug bug that is reproduced very rarely (once per several dozens of trys).
I'm inside of render call and want to find out as much information as possible from there:
What caused rerender: forceUpdate, setState or props changed?
If it was a props change, which component initiated chain of rerenders: I mean not the fact of parent render, but the top component from parents chain that has used setState or forceUpdate and so caused rerender of itself and the whole tree bellow (including the component I'm currently in).
It's guaranteed that all components are class components (not functional) and I'm using react 16.4.2 including deprecated lifecycle methods (if it is important). There are some usages of context too.
How can I make it? Note, I'm asking about debug techniques, not about fixing my concrete bug.
If your component is a pure component - extends React.PureComponent { ... }, you don't really have to care about the whole chain of re-renders, since it will re-render only if props have changed (from the chain or from the redux store).
It will not re-render if parent state changed or if parent basically has re-rendered.
However, it will still re-render - as I mentioned above - if props have changed or state inside that component was updated or forceUpdate function was called.
If you are not calling forceUpdate inside your component or you are not updating the state, the issue may be related with the props.
You could use e.g. componentDidUpdate and simply compare the prevProps with this.props and check which one of the props has changed.
Nonetheless, you can also check https://www.npmjs.com/package/#welldone-software/why-did-you-render package, it might be helpful for you.

Redux: How do partial re-renderings work?

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.

MobX: Avoid triggering re-render when object keys are not used in views

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

Categories