React useState hook performance on big objects - reactjs

I'm new to React and I am creating an application where I am using a quite big state with frequent updates. Using useState() I understand it will replace the whole object on every update. If that means it will make a full copy of the object, there will be a severe performance hit in m case. If it is some lazy evaluation, I think I might be fine, hence my question.
Contrary, if I would use the old class based setState() method, I could update only the necessary parts of the state. For instance, my data structure looks something like this:
{
'data0': { ... some not very deep object ...},
'data1': { ... },
'data2': { ... },
...,
'dataN': { ... },
}
where I can potentially have thousands of data objects. As the data objects are quite small, replacing them when needed is not that much of a performance hit, which is perfectly doable with setState() in a class, but how is this going to work if using the useState() hook?

U can spread previous state with usestate and u will get same result as setstate
Usestate([
...state,
Data6
])

Related

Alternative way to handle state in React using memo

When it comes to handling complex state in React everybody suggests to flatten the state to avoid something like this just to update a single property:
setState({ …state, user:{ …state.user, profile:{…state.user.profile, address:{…state.user.profile.address, city:’Newyork’}} }});
Which is really cubersome to work with. There is another way: use an object holding your state and return that from a memoized function. Then whenever you made a change simply force a re-render.
// note the reference cannot be changed, but values can.
const data = useMemo(() => ({
user: {
name: "",
profile: {
address: {
city: "New york"
}
}
}
}), []);
// use dummy data to trigger an update
const [toggle, setToggle] = useState(false);
function forceUpdate() {
setToggle(prev => !prev);
}
function makeChanges() {
// make any change on data without any copying.
data.user.address.city = "new city name";
// hydrate the changes to the view when you're done
forceUpdate();
}
return (
<div onClick={() => makeChanges()}>{data.user.address.city }</div>
)
Which works perfectly. Even with massive and complex data structures.
From what I can tell state is really just a memoized values which will trigger an update upon change.
So, my one question: What is the downside of using this?
The docs say useMemo is not a guarantee:
You may rely on useMemo as a performance optimization, not as a semantic guarantee. In the future, React may choose to “forget” some previously memoized values [...]
If you'd really want to do something like this and you are absolutely positively sure you're willing to do things unlike anyone else in React land, you'd use useRef for state storage that doesn't cause rerenders by itself. I'm not going to add an example of that, because I don't recommend it in the least.
You should also note that your method will not cause memoized (React.memo()) components to rerender, since they will not "see" changes to props if their identity does not change. Similarly, if another component uses one of your internally mutated objects as a dependency for e.g. an effect, those effects will not fire. Finding bugs caused by that will be spectacularly annoying.
If modifying deep object structures is otherwise cumbersome, see e.g. the Immer library, which does Proxy magic internally to let you modify deep objects without trouble – or maybe immutability-helper if you're feeling more old-school.

How to use an array as a dependency of a React hook

I have a component that has a callback. It depends on an array of plain old objects stored in redux which won't change very often while the component itself will change its state pretty frequently. Some subcomponents should be rerendered on those state changes, but the one that uses the callback, should not.
What's the best approach to making an array a dependency of useCallback()? So far, I've been using
const handleAllItemsSelectedChange = useCallback(
checked => {
if (checked) {
dispatch(setSelected(items));
} else {
dispatch(selectSelected([]));
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[JSON.stringify(items)]
);
This doesn't seem ideal, and potentially slower than just rerendering the component every time. I can't imagine this isn't a very common use-case. The React team surely has a best practice for this, right? I can't find it in the documentation.
JSON.stringify or any deep comparison is going to be inefficient and slow. React has no plans to support it
Depending on whether you add or remove items (if not mutating the objects) you can just compare with items.length. Or you could possibly save performance by just creating the function each time, as opposed to trying to save performance putting it in a useCallback.
It's a case by case scenario
In redux reducer every time the array changes you have to create new array. So, your array becomes immutable and you can use it for dependency by reference. Example below just demonstrates the principle.
function reducer(state, action) {
switch(action.type) {
case "addItem":
return {...state, items: [...state.items, action.value]};
case "changeProp":
return {...state, prop: action.value}
default:
return state;
}
}
As you can see every time the array changes you'll get the new instance of the array. That means you can use it by reference and don't need to strignify it anymore:
const handleAction = useCallback(checked=>{
....
}, [items]);
By the way immutability is the approach recommended by redux documentation

React, avoid rerendering with shallowEqual

I'm starting to see performance problems and trying to optimize it.
As a first step, I'm dealing with Perf.printWasted()
That is I'm trying to eliminate unnecessary renders.
One of my component is being rerendered because of two props
a new date object.
newly created [todo] array
Suppose you are creating a calendar for todo.
For each date, I'm passing a date, and list of todos which are due that day.
I'm doing something like (simplified)
todoForDay = _.filter(todos, (todo) => {return todo.dueDate == today})
react's shallowEqual wouldn't see those two cases as equal, how should I proceed?
For #1, I could think of passing moment(date).format() as props and converting back to date object every time I pass the date.
But it would get really tiresome, because there are so many child components that needs access to the date.
Have you tried to implement the shouldComponentUpdate lifecycle method? You could check for the inequality of the passed in date prop and todos array like so:
class MyComponent extends Component {
shouldComponentUpdate(prevProps) {
const {
date,
todos,
} = this.props;
const {
date: prevDate,
todos: prevTodos,
} = prevProps;
return (
date.getTime() !== prevDate.getTime() ||
!_.isEqual(todos, prevTodos)
);
}
render() {
// render...
}
}
The _.isEqual method performs a deep equality comparison of the two todos arrays. There is also a _.isEqualWith method you could use to define your own notion of equality for those arrays if you want to be more specific.
Alternatively, you could look into something like Immutable.js as it would allow you to do an easier todos !== prevTodos comparison, but this might be overkill for your needs (depending on how much data you're working with).
If you're already doing something like this, perhaps provide some more code (your implemented shouldComponentUpdate method so we can suggest other alternatives).
For #1 you don't need to convert the prop. You can simply compare the dates with getTime() in shouldComponentUpdate():
shouldComponentUpdate(nextProps) {
return this.props.date.getTime() !== nextProps.date.getTime()
}
And for #2 unfortunately it looks like an array which contains objects, I think doing a deep equal here is more expensive than just a render.
Note that executing render() doesn't mean that the DOM will get an update. If you setup key properly then it should be fast enough. (If the todos may change its order or the newly added todo is added on top then don't use indexes as the key. Real unique keys are better in that case)
You should try to avoid unnecessary setState (if you are not using a state management library). Also try to split your components to small pieces. Instead of re-rendering a huge component every time it has an update, updating only the minimum sections of your app should be faster.
Another possibility is to re-structure your state. But it's based on your requirements. If you don't need the full datetime of each todo, you can group your state something like:
todos: {
'2017-04-28': ['Watch movie', 'Jogging'],
'2017-04-29': ['Buy milk']
}
By doing this you don't even need the filter. You can grab the todos of the date your want easily.
In a more complex case which you need more information, you can try to normalize your state, for example:
{
todos: {
1: { text: 'Watch movie', completed: true, addedTime: 1493476371925 },
2: { text: 'Jogging', completed: true, addedTime: xxxxxxxxxx},
3: { text: 'Buy milk', completed: false, addedTime: xxxxxxxxxx}
},
byDate: {
'2017-04-28': [1, 2],
'2017-04-29': [3]
}
}
Now if add a new todo to the todos, it won't affect your component which is referring to byDate so you can make sure that there is no unnecessary re-renders.
I'm sharing my solutions.
For calendar based todo list, I wanted to avoid implementing shouldComponentUpdate for every subcomponents for a calendar day.
So I looked for a way to cache the dates I created for the calendar. (Unless you change the month, you see the same range of dates) .
So https://github.com/reactjs/reselect was a great fit.
I solved #2 with the reselect as well.
It memoizes (caches) function result until function params change.

What is the use of immutable.js while using redux?

This is something I'am not getting right.
While using redux, in reducers we use the spread operator.
For e.g.
{...state,data : action.payload,fetching:false}
That is a new state object is created, rather than mutating the correct state right? (Please correct me if i'am wrong)
In such cases what is the use of immutableJS ??
It performs the same action as mentioned above right??
You are correct, the example you have shown is creating a new object and not mutating the state. It is fine for many cases, so if you don't feel that ImmutableJS is going to add anything for you, don't use it.
ImmutableJS was more useful before the spread operator was in common use in ES6 (I believe it is technically still only a proposal). If you are not using ES6, then the alternative is to use Object.assign which can get very messy, very quickly, especially with more nested structures.
ImmutableJS is still useful if you need to modify a single node deep within the state tree, but if this is the case, you can generally get around it by structuring the data in a different way.
When you have a simple flat state, you can easily manage it without extra libraries.
But let's consider something more complex, like the following
{
users: {
123: {
name: 'John',
lastName: 'Doe'
},
345: {
name: 'Bob',
lastName: 'Jack'
}
....
}
}
If you want to update a name for some user, it will be not so trivial
return {
...state,
users: {
...state.users,
[action.userId]: {
...state.users[action.userId],
name: action.newName
}
}
Pretty much code, isn't it? At this moment, you may want to look for another solution and immutable.js may help you do the same with one line:
state.setIn(['users', action.userId, 'name'], action.newName)
Making your state immutable ensures you that the state will not get modified outside of flux-flow. In very complex structures with a lot of levels and props being passed around it, it prevents the state from being mutated accidentally.

What is the best implememtation of react shouldComponentUpdate with immutable.js

I'm new to ImmutableJS. My app implements large Redux Store & multiple react components.
Correct me if I'm wrong:
I understand that the benefits of Immutable is to protect Flux Store and to avoid unnecessary vDom rendering on component getting unchanged props.
To benefit from better rendering performance with ImmutableJS, shouldComponentUpdate() must be implemented.
What is the best implementation of this function?
I already found several implementations of it, all using shallowEqual() with some modifications:
Facebook implements shallowEqual for React and more I imagine.
Jurassix offers an implementation that implements shallowEqualImmutable. It the function from Facebook except that the is() function is replaced by the one given by ImmutableJS. The first equality is different too.
Dan does the same thing with a different shalllowEqual function that implement parts of the two previous implementation.
Someone knows which implementation I should use in my case? or none and implement specific shouldComponentUpdate()? I am slightly at a loss on this point
Thank you a lot for any help!!
I understand that the benefits of Immutable is to protect Flux Store and to avoid unnecessary vDom rendering on component getting unchanged props.
This is not really related to Immutable (if you mean the library). For example, you can use plain objects and arrays with Redux but since Redux asks you to never mutate them, you get pretty much the same benefits in most cases. So Immutable library can offer a nicer API for updating things immutably, but it is not required for performance optimizations if you don’t mutate plain objects or arrays.
To benefit from better rendering performance with ImmutableJS, shouldComponentUpdate() must be implemented.
Again, not really related to ImmutableJS, but yes, to benefit from immutability in props, you’d need to implement shouldComponentUpdate(). However if you use Redux you probably already use connect() from React Redux package which implements shouldComponentUpdate() for you for most cases. So you don’t really need to write it by hand for any connect() ed components.
Someone knows which implementation I should use in my case? or none and implement specific shouldComponentUpdate()? I am slightly at a loss on this point
If you don’t have performance problems, don’t use either. React by itself is fairly performant in most cases, and a connect() on top of it will add a good default implementation of shouldComponentUpdate().
For components that are not connect()ed but still get frequently updated, I would suggest you to use react-addons-shallow-compare. It is used by PureRenderMixin internally but since mixins are not really used in modern React APIs, a separate function can be more convenient.
If you want special support for Immutable.is, you can indeed use something like shallowEqualImmutable. It understands Immutable collections better, as it considers lists of the same values to be the same. At this point you would be better off profiling different implementations against your app, as the specifics can vary depending on your use case.
Don’t optimize prematurely, make sure this is an actual problem before solving it.
I was also using a large Redux Store, and found that using the Immutable.js can make the accessing of the state complicated, e.g., nested2.getIn(['a', 'b', 'd']) vs nested2.a.b.d; What I really need is to make sure I don't mutate the state in my reducers, and still be able to check the equality using === in the shouldComponentUpdate() method.
I have created https://github.com/engineforce/ImmutableAssign to fulfill my requirements. It is a light weigh immutable helper, which supports immutability and allows you to continue working with POJO (Plain Old JavaScript Object), so our React components can read the state as usual, e.g.,
return newState.a.b.d === oldState.a.b.d;
Example,
var iassign = require("immutable-assign");
var o1 = { a: { b: { c: [[{ d: 11, e: 12 }], [{ d: 21, e: 22 }]], c2: {} }, b2: {} }, a2: {} };
//
// Calling iassign() to push new item to o1.a.b.c[1]
//
var o2 = iassign(
o1,
function (o) { return o.a.b.c[1]; }, // get property to be updated
function (c) { // update select property
c.push(101);
return c;
}
);
// o2.a.b.c[1][1] === 101
// o1 is not modified
// o2 !== o1
// o2.a !== o1.a
// o2.a.b !== o1.a.b
// o2.a.b.c !== o1.a.b.c
// o2.a.b.c[1] !== o1.a.b.c[1]
// o2.a2 === o1.a2
// o2.a.b2 === o1.a.b2
// o2.a.b.c2 === o1.a.b.c2
// o2.a.b.c[0] === o1.a.b.c[0]
// o2.a.b.c[0][0] === o1.a.b.c[0][0]
// o2.a.b.c[1][0] === o1.a.b.c[1][0]

Resources