useEffect 在与 useReducer 一起使用时不会触发重新渲染

useEffect not triggering re-render when it's being used with useReducer

即使状态已更改,我也无法触发重新渲染。 PageContainer 调用 loadPageloadPage 更新状态没有任何问题。 但是当状态改变时,它不会触发重新渲染。 它只显示初始状态(pageName.loginPage)。我的预期结果是 pageName.profilePage,因为令牌已存储在浏览器中。我还检查了调试器状态是否明显更改为 pageName.profilePage

function PageContainer() {
    const { state, loadPage } = useContainer({
        reducer: loginStatusCheckReducer,
    });

    useEffect(() => {
        loadPage();
    }, [state]); // or [state.page]

    return (
        <>
           {state.page}
        </>
    );
}

这里是 useContainer

function useContainer({ reducer }) {
    const [state, dispatch] = useReducer(reducer, { page: pageName.loginPage });
    const loadPage = () => {
        dispatch({ type: actionType.loadPage, dispatch });
    };

    return { state, loadPage };
}

这是reducer函数

function loginStatusCheckReducer(state, action) {
    if (action.type === actionType.loadPage) {
        const token = localStorage.getItem("token");
        if (token) {
            state.api = api(token);
            state.page = pageName.profilePage;
            return state;
        }
    }

    return state;
}


初始状态:

loadPage 之后

查看代码,我猜这不会触发重新渲染,因为您的 useEffect 正在传递一个空数组,因此它不会对任何状态变化做出反应。

尝试添加 variable/state ,一旦加载到 useEffect

就会发生变化
function PageContainer() {
const { state, loadPage } = useContainer({
    reducer: loginStatusCheckReducer,
});

useEffect(() => {
    loadPage();
}, [state]); // here the effect will listen to state changes

console.log('state.page', state.page);

return (
    <>
       <h1>{state.page}</h1>
    </>
);}

以下代码应该可以解决这个问题。 @lon 已经指出,state 不应该被直接改变。

function loginStatusCheckReducer(state, action) {
    if (action.type === actionType.loadPage) {
        const token = localStorage.getItem("token");
        if (token) {
            //state.api = api(token);
            //state.page = pageName.profilePage;
            //return state;

            return {
                ...state,
                api: api(token),
                page: pageName.profilePage,
            };
        }
    }
}