为什么 useReducer 的调度会导致重新渲染? [英] Why is useReducer's dispatch causing re-renders?

查看:45
本文介绍了为什么 useReducer 的调度会导致重新渲染?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Suppose I implement a simple global loading state like this:

// 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);

然后假设我有一个组件可以改变加载状态,但从不消耗它,就像这样:

Then suppose I have a component that mutates the loading state, but never consumes it, like this:

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 可以像静态值一样对待".

According to useReducer docs, dispatch is has a stable identity. I interpreted this to mean that when a component extracts dispatch from a useReducer, it won't re-render when the state connected to that dispatch changes, because the reference to dispatch will always be the same. Basically, dispatch can "treated like a static value".

然而,当这段代码运行时,dispatch(actionCreators.setLoadingOn()) 行触发了对全局状态的更新,并且 useLoading 钩子再次运行,<代码>dispatch(actionCreators.setLoadingOn()) (无限重新渲染-_-)

Yet when this code runs, the line dispatch(actionCreators.setLoadingOn()) triggers an update to global state and the useLoading hook is ran again and so is dispatch(actionCreators.setLoadingOn()) (infinite re-renders -_-)

我是不是没有正确理解 useReducer?或者我正在做的其他事情可能会导致无限重新渲染?

Am I not understanding useReducer correctly? Or is there something else I'm doing that might be causing the infinite re-renders?

推荐答案

第一个问题是你不应该在渲染时触发任何 React 状态更新,包括 useReducersdispatch()useState 的设置器.

The first issue is that you should never trigger any React state updates while rendering, including useReducers's dispatch() and useState's setters.

第二个问题是,调度 while 总是会导致 React 将状态更新排队并尝试调用 reducer,如果 reducer 返回一个新值,React 将继续重新渲染.无论您从哪个组件分派 - 导致状态更新和重新渲染是 useReducer 的首要任务.

The second issue is that yes, dispatching while always cause React to queue a state update and try calling the reducer, and if the reducer returns a new value, React will continue re-rendering. Doesn't matter what component you've dispatched from - causing state updates and re-rendering is the point of useReducer in the first place.

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

The "stable identity" means that the dispatch variable will point to the same function reference across renders.

这篇关于为什么 useReducer 的调度会导致重新渲染?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆