#javascript #reactjs #diff #memo
Вопрос:
React.js версия: v16.8.2
Использование контекста в сочетании с useReducer в функциональных компонентах, когда я изменил какое-то состояние, привело к тому, что все дочерние компоненты были обернуты контекстом.Поставщик», подлежащий повторному отображению. Что я должен сделать, чтобы предотвратить ненужную повторную визуализацию этих дочерних компонентов?
Теперь я использую «useMemo», чтобы обернуть структуру DOM всех дочерних компонентов.
Но что касается этого подхода, я хотел бы знать, влияет ли он на оптимизацию производительности? Потому что это может привести только к кэшированию структуры DOM, но ее собственные функциональные компоненты все равно будут повторно выполнены.
В то же время я также хочу знать, будет ли снова выполняться логика алгоритма diff для структуры DOM кэша «useMemo», который я использую?
Это мой код.
- Корневой компонент:
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: {}
})
Ответ №1:
Разделиться 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>
)
}
тогда у него все еще есть те же дочерние элементы, которые он получил от основного раньше, но React не будет повторно посещать это поддерево при повторном рендеринге.