Почему рассылка useReducer вызывает повторные рендеры? - PullRequest
1 голос
/ 01 февраля 2020

Предположим, я реализую простое глобальное состояние загрузки, например:

// 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, он не будет повторно визуализироваться при изменении состояния, связанного с этой диспетчеризацией, поскольку ссылка на диспетчеризацию всегда будет одинаковой. По сути, диспетчеризация может «обрабатываться как статическое c значение».

Тем не менее, когда этот код выполняется, строка dispatch(actionCreators.setLoadingOn()) инициирует обновление глобального состояния, и ловушка useLoading запускается снова, и поэтому dispatch(actionCreators.setLoadingOn()) (бесконечное повторное рендеринг -_-)

Не правильно ли я понимаю useReducer? Или я делаю что-то еще, что может вызывать бесконечное повторное рендеринг?

1 Ответ

3 голосов
/ 01 февраля 2020

Первая проблема заключается в том, что вы никогда не должны запускать какие-либо обновления состояния React при рендеринге, включая сеттеры useReducers dispatch() и useState.

Вторая проблема заключается в том, что yes, диспетчеризация Хотя React всегда ставит в очередь обновление состояния и пытается вызвать редуктор, а если редуктор возвращает новое значение, React продолжит повторную визуализацию. Неважно, из какого компонента вы отправили - вызывая обновления состояния и повторный рендеринг - это, в первую очередь, точка useReducer.

«Стабильная идентификация» означает, что переменная dispatch будет указывают на одну и ту же ссылку на функцию при рендеринге.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...