温馨提示:本文翻译自stackoverflow.com,查看原文请点击:javascript - Why is useReducer's dispatch causing re-renders?
javascript react-hooks reactjs redux use-reducer

javascript - 为什么useReducer的分派会导致重新渲染?

发布于 2020-04-09 11:25:20

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

// 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()) (无限重新渲染-_-)

我不是正确理解useReducer吗?还是我正在做的其他事情可能导致无限重新渲染?

查看更多

提问者
adrayv
被浏览
88
markerikson 2020-02-01 06:49

第一个问题是,你应该永远不会触发任何阵营状态更新,同时呈现,包括useReducersdispatch()useState的制定者。

第二个问题是,是的,在分派的同时总是使React排队状态更新并尝试调用化简器,如果化简器返回新值,React将继续重新渲染。不管您从哪个组件派遣了什么-首先要引起状态更新和重新渲染useReducer

“稳定的身份”表示dispatch变量将跨渲染指向相同的函数引用。