React.js version: v16.8.2
Using Context combined with useReducer in functional components, when I changed some state, caused all the child components wrapped by 'Context.Provider' to be re-rendered. What should I do to prevent some unnecessary re-rendering of these child components?
Now, I use 'useMemo' to wrap the DOM structure of all child components.
But with regard to this approach, I would like to know whether it has the effect of optimizing performance? Because this can only cause the DOM structure to be cached, but its own functional components will still be re-executed.
At the same time, I also want to know whether the diff algorithm logic will be executed again for the DOM structure of the 'useMemo' cache that I use?
This is my code.
- Root component:
import React, { useReducer } from 'react'
import * as styles from './home.scss'
import { Context } from './context.js'
import Component1 from './component1'
import Component2 from './component2'
import Component3 from './component3'
const Main = () => {
const initState = {
count: 0
}
const reducer = (state, action) => {
switch (action.type) {
case 'add':
return {
...state,
count: action.payload.count
}
default:
return state
}
}
const [state, dispatch] = useReducer(reducer, initState)
return (
<Context.Provider value={{ state, dispatch }}>
<div className={styles.wrapper}>
<Component1 />
<Component2 />
<Component3 />
</div>
</Context.Provider>
)
}
export default Main
- One of child components
import React, { useContext, useCallback, useMemo } from 'react'
import * as styles from '../home.scss'
import { Context } from '../context.js'
const Component2 = () => {
console.log(2)
const { state, dispatch } = useContext(Context)
const addClick = useCallback(() => {
dispatch({
type: 'add',
payload: {
count: 3
}
})
}, [])
return (
useMemo(() => {
return (
<div className={styles.component2}>
{console.log(2 + '!')}
<button onClick={addClick}>add</button>
<div>{state.count}</div>
</div>
)
}, [addClick, state.count])
)
}
export default Component2
- Context
import React from 'react'
export const Context = React.createContext({
dispatch: () => {},
state: {}
})
Split
Main
into two. Right now, when the reducer changes, the whole Main component re-renders as well, including all the<ComponentN>
. But, if you do this:and you change
Main
to be:then it still has the same children prop it got from the Main before, but React will not re-visit that subtree when re-rendering.