javascript - 在功能组件中使用 'Context' 和 'useReducer' 会导致所有子组件重新渲染
问题描述
React.js 版本:v16.8.2
在功能组件中使用 Context 与 useReducer 结合,当我更改某些状态时,会导致所有由 'Context.Provider' 包裹的子组件被重新渲染。我应该怎么做才能防止对这些子组件进行一些不必要的重新渲染?
现在,我使用 'useMemo' 来包装所有子组件的 DOM 结构。
但是关于这种做法,我想知道它是否有优化性能的效果?因为这样只会导致DOM结构被缓存,但它自己的功能组件还是会被重新执行。
同时我也想知道我使用的‘useMemo’缓存的DOM结构是否会再次执行diff算法逻辑?
这是我的代码。
- 根组件:
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
- 子组件之一
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
- 语境
import React from 'react'
export const Context = React.createContext({
dispatch: () => {},
state: {}
})
解决方案
一Main
分为二。现在,当 reducer 发生变化时,整个 Main 组件也会重新渲染,包括所有<ComponentN>
. 但是,如果你这样做:
function MyProvider({ children }) {
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)
const value = React.useMemo(() => ({ state, dispatch }), [state, dispatch])
return (
<Context.Provider value={value}>
{children}
</Context.Provider>
)
}
你变成Main
了:
const Main = () => {
return (
<MyProvider>
<div className={styles.wrapper}>
<Component1 />
<Component2 />
<Component3 />
</div>
</MyProvider>
)
}
那么它仍然具有之前从 Main 获得的相同 children prop,但是 React 在重新渲染时不会重新访问该子树。
推荐阅读
- assembly - 非法指令:PRINTN
- android - Espresso 测试无法通过“依赖冲突”构建
- ios - Xcode 倒计时几天,直到圣诞节
- javascript - 用 html 和 javascript 编写画布
- list - 试图了解如何不将元素添加到列表中
- python - tf.metrics.accuracy 返回的第一个值代表什么
- php - PHP 无法使用在 Apache + PHP-fpm 中没有“php”扩展且没有“R”标志的重写规则
- java - JNI:在 Linux 下安装 openCV 时没有
- javascript - 是否可以更改传递给函数的引用?
- go - 使用 errorf 而不是 sprintf 使用错误