假设我实现了一个简单的全局加载状态,如下所示:
// 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 文档,dispatch 具有稳定的身份。我将此解释为当一个组件从 useReducer 中提取 dispatch 时,它不会在连接到该 dispatch 的状态发生变化时重新渲染,因为对 dispatch 的引用将始终相同。基本上,调度可以“像静态值一样对待”。
然而,当此代码运行时,该行dispatch(actionCreators.setLoadingOn())
会触发对全局状态的更新,并且useLoading
钩子会再次运行,因此dispatch(actionCreators.setLoadingOn())
(无限重新渲染 -_-)
我没有正确理解 useReducer 吗?或者我正在做的其他事情可能会导致无限重新渲染?