Предположим, я реализую простое глобальное состояние загрузки, например:
// 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? Или я делаю что-то еще, что может вызывать бесконечное повторное рендеринг?