Mobx
is a useful library to help manage state in react
app easily and effectively, compared to redux
, I personally feel that mobx
has some advantages such as simplicity; easy to expand as the app grows; organize data according to store classes; mobx automatically detect store changes to optimize render component without regard to immutable as in redux; don’t need as many related libraries as in redux; Code organization, directory structure is simple and, finally, easy to learn for novices.
There have been a lot of articles related to basic mobx
, now I just talk a little bit about mobx
before starting to talk about optimizing the rendering react component with mobx.
- First, the State here is considered as a place to store data structures for the app, the state structure here can include objects, arrays, primitives, references. Example state contains an array todos list ( @observable )
- Next is Derivations , the things that are calculated automatically if the
state
changes are calledderivations
, you need to visualize the derivations with the following notation: state changes => automatically computes from this state => returns a new value: can be data, JSX code, … ( @computed ) - Next is Reactions, similar to derivations, but instead of returning a new value, the reactions will automatically run a certain task, reactions are visualized as follows: state changes => automatically runs the task related to the state. This is like a render component, running an async networking task, … ( @autorun , @observer )
- Finally Actions, which are simply functions that change application state, there is a very important rule we should follow is to only change state through actions ( @action ).
To conclude, the flow of mobx is as simple as follows: actions that change state, derivations related to this state will be automatically calculated, reactions related to the state will be automatically executed.
Just as simple as that, here I will go to the optimize render, and the basic mobx section, you can refer to many previous articles.
Optimized React component rendering
Use and split into many components
@observer components will track all the data it uses and will re-render if this data changes. So the more components are broken down, the number of components that need re-rendering will decrease.
Should separate a component for use exclusively for rendering list items
When a list has a large number of items, it is necessary to create a separate component that is only used to render the list without rendering other data outside this list. This is useful if other data changes then our render list component won’t need to re-render, for example
Bad:
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">const</span> MyComponent <span class="token operator">=</span> <span class="token function">observer</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter"><span class="token punctuation">{</span> todos <span class="token punctuation">,</span> user <span class="token punctuation">}</span></span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span> div <span class="token operator">></span> <span class="token punctuation">{</span> user <span class="token punctuation">.</span> name <span class="token punctuation">}</span> <span class="token operator"><</span> ul <span class="token operator">></span> <span class="token punctuation">{</span> todos <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token parameter">todo</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span> TodoView todo <span class="token operator">=</span> <span class="token punctuation">{</span> todo <span class="token punctuation">}</span> key <span class="token operator">=</span> <span class="token punctuation">{</span> todo <span class="token punctuation">.</span> id <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> ul <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> div <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> |
In the above example, if the user.name
changes, the todos list will be recalculated to render, which greatly affects performance.
Good:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token keyword">const</span> MyComponent <span class="token operator">=</span> <span class="token function">observer</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter"><span class="token punctuation">{</span> todos <span class="token punctuation">,</span> user <span class="token punctuation">}</span></span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span> div <span class="token operator">></span> <span class="token punctuation">{</span> user <span class="token punctuation">.</span> name <span class="token punctuation">}</span> <span class="token operator"><</span> TodosView todos <span class="token operator">=</span> <span class="token punctuation">{</span> todos <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> div <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">const</span> TodosView <span class="token operator">=</span> <span class="token function">observer</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter"><span class="token punctuation">{</span> todos <span class="token punctuation">}</span></span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span> ul <span class="token operator">></span> <span class="token punctuation">{</span> todos <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token parameter">todo</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span> TodoView todo <span class="token operator">=</span> <span class="token punctuation">{</span> todo <span class="token punctuation">}</span> key <span class="token operator">=</span> <span class="token punctuation">{</span> todo <span class="token punctuation">.</span> id <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> ul <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> |
Do not use indexes as key prop when rendering lists
Do not use indexes or something that will change in the future as key prop, since these values React will not distinguish each item in the list if re-rendered, which results in react creating a new one. all other components. The best way is to use an id attached to that item as the key props.
Bad:
1 2 3 4 5 6 7 8 | <span class="token keyword">const</span> TodosView <span class="token operator">=</span> <span class="token function">observer</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter"><span class="token punctuation">{</span> todos <span class="token punctuation">}</span></span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span> ul <span class="token operator">></span> <span class="token punctuation">{</span> todos <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter">todo <span class="token punctuation">,</span> index</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span> TodoView todo <span class="token operator">=</span> <span class="token punctuation">{</span> todo <span class="token punctuation">}</span> key <span class="token operator">=</span> <span class="token punctuation">{</span> index <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> ul <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> |
Good:
1 2 3 4 5 6 7 8 | <span class="token keyword">const</span> TodosView <span class="token operator">=</span> <span class="token function">observer</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter"><span class="token punctuation">{</span> todos <span class="token punctuation">}</span></span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span> ul <span class="token operator">></span> <span class="token punctuation">{</span> todos <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token parameter">todo</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span> TodoView todo <span class="token operator">=</span> <span class="token punctuation">{</span> todo <span class="token punctuation">}</span> key <span class="token operator">=</span> <span class="token punctuation">{</span> todo <span class="token punctuation">.</span> id <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> ul <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> |
Get observable data (dereference) as late (deep) as possible
Mobx will re-render the dereference component automatically, the deeper we deference, the less the component will re-render, a bit confusing so we will go into the following example.
Slower:
1 2 3 4 5 | <span class="token operator"><</span> Profile <span class="token operator">></span> <span class="token operator"><</span> OtherComponent <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> DisplayName name <span class="token operator">=</span> <span class="token punctuation">{</span> person <span class="token punctuation">.</span> name <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> Profile <span class="token operator">></span> |
In this example, when the property name changes, the Profile component will re-render, because the component Profile has a direct get person.name (deference in mobx).
Faster:
1 2 3 4 5 | <span class="token operator"><</span> Profile <span class="token operator">></span> <span class="token operator"><</span> OtherComponent <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> DisplayName name <span class="token operator">=</span> <span class="token punctuation">{</span> person <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> Profile <span class="token operator">></span> |
In this example, when the property name changes, only the DisplayName component is re-rendered, and the Profile does not re-render, because the component Profile does not get person.name directly.
Conclude
Above are tips we can apply to optimize the react component render when using mobx, thank you for watching.
Reference: https://mobx.js.org/