为什么useReducer的调度会导致重新渲染?



假设我实现了一个简单的全局加载状态,如下所示:

// hooks/useLoading.js
import React, { createContext, useContext, useReducer } from 'react';
const Context = createContext();
const { Provider } = Context;
const initialState = {
isLoading: false,
};
function reducer(state, action) {
switch (action.type) {
case 'SET_LOADING_ON': {
return {
...state,
isLoading: true,
};
}
case 'SET_LOADING_OFF': {
return {
...state,
isLoading: false,
};
}
}
}
export const actionCreators = {
setLoadingOn: () => ({
type: 'SET_LOADING_ON',
}),
setLoadingOff: () => ({
type: 'SET_LOADING_OFF',
}),
};
export const LoadingProvider = ({ children }) => {
const [{ isLoading }, dispatch] = useReducer(reducer, initialState);
return <Provider value={{ isLoading, dispatch }}>{children}</Provider>;
};
export default () => useContext(Context);

然后假设我有一个组件,它改变了加载状态,但从不使用它,如下所示:

import React from 'react';
import useLoading, { actionCreators } from 'hooks/useLoading';
export default () => {
const { dispatch } = useLoading();
dispatch(actionCreators.setLoadingOn();
doSomethingAsync().then(() => dispatch(actionCreators.setLoadingOff()))
return <React.Fragment />;
};

根据useReducer文档,调度具有稳定的标识。我将其解释为,当组件从useReducer中提取调度时,当连接到该调度的状态更改时,它不会重新呈现,因为对调度的引用将始终相同。基本上,调度可以"像静态值一样处理"。

然而,当此代码运行时,dispatch(actionCreators.setLoadingOn())行会触发对全局状态的更新,并且再次运行useLoading钩子,dispatch(actionCreators.setLoadingOn())也是如此(无限重新渲染 -_-(

我是否正确理解使用减速器?还是我正在做的其他事情可能导致无限重新渲染?

第一个问题是,在渲染时永远不应该触发任何 React 状态更新,包括useReducersdispatch()useState的 setter。

第二个问题是,是的,调度时总是会导致 React 排队状态更新并尝试调用化简器,如果化简器返回新值,React 将继续重新渲染。 无论您从哪个组件调度 - 首先要useReducer状态更新和重新渲染。

"稳定标识"意味着dispatch变量将跨渲染指向相同的函数引用。

除了如前所述,您在渲染时设置状态这一事实之外,我想我可以阐明如何利用调度的稳定身份来避免不必要的重新渲染,就像您所期望的那样。

提供程序值是一个对象(值={{ isLoad, dispatch}}(。这意味着当上下文的状态发生变化时(例如,当 isLoad 发生变化时(,值本身的标识将发生变化。因此,即使您有一个使用调度的组件,如下所示:

const { dispatch } = useLoading()

当加载更改时,组件将重新呈现。

如果您觉得重新渲染失控,则利用调度稳定标识的方法是创建两个提供程序,一个用于状态(在本例中为 isLoad(,一个用于调度,如果您这样做,则只需要调度的组件如下所示:

const dispatch = useLoadingDispatch()

加载更改时不会重新渲染。

请注意,这可能是过度优化,在简单的情况下可能不值得。

这是一组出色的文章,可进一步阅读该主题: https://kentcdodds.com/blog/how-to-optimize-your-context-value https://kentcdodds.com/blog/how-to-use-react-context-effectively

相关内容

  • 没有找到相关文章

最新更新