Использование ловушки useState в useEffect на history.listen - PullRequest
0 голосов
/ 27 октября 2019

У меня проблемы с useState при прослушивании history изменений в useEffect.

Когда меняется pathname, инициируется setState, но затем добавляется stateназад.

Например, у меня есть компонент flag, который собирает группы уведомлений, но при изменении pathname я хочу, чтобы все флаги были сняты и удалены из state.

Компонент флага

const PageFlag = ({ history }: InterfaceProps) => {
const { contextData, dismissFlag, dismissAllFlags } = useContext(GlobalConsumer);

  useEffect(() => {
    history.listen(() => {
      dismissAllFlags();
    });
  });

  return (
    <>
      <FlagGroup onDismissed={dismissFlag}>
        {contextData.flags.map((flag, index) => (
          <Flag key={index} {...flag} />
        ))}
      </FlagGroup>
    </>
  );
};

Хронология истории используется с import { withRouter } from 'react-router-dom'

Состояние и функция для dismissAllFlags отображаются в компоненте createContextas

const DefaultState: InterfaceState = {
  otherStateExample: false,
  flags: []
};

export const GlobalConsumer = createContext({
  contextData: DefaultState,
  addFlag: (flagData: any) => {},
  dismissFlag: () => {},
  dismissAllFlags: () => {}
});

export const GlobalProvider = ({ children }: InterfaceProps) => {
  const [state, setState] = useState<InterfaceState>({
    ...DefaultState
  });

  return (
    <GlobalConsumer.Provider
      value={{
        contextData: state,
        addFlag: (flagData: any) => {
          setState({ ...state, flags: [flagData].concat(state.flags) });
        },
        dismissFlag: () => {
          setState({ ...state, flags: state.flags.slice(1) });
        },
        dismissAllFlags: () => {
          setState({ ...state, flags: [] });
        }
      }}
    >
      {children}
    </GlobalConsumer.Provider>
  );
};

Возникает проблема: при изменении pathname, dismissAllFlags использует setState для установки flags в качестве [], но затем добавляет предыдущее состояние с flags.

Как я могу удалить все flags, но помните текущий state для других items?

Ответы [ 3 ]

1 голос
/ 01 ноября 2019

Мы используем это так:

const [isOpen, setIsOpen] = useState(false);
useEffect(() => {
    history.listen(() => setIsOpen(false));
  }, [history]);

1 голос
/ 31 октября 2019

Вы пропускаете второй входной параметр в useEffect(), что приведет к тому, что слушатель будет читаться при каждом рендеринге.

Это должно выглядеть так: обратите внимание, вам также не нужна внутренняя функция.

useEffect(() => {
  history.listen(dismissAllFlags)
}, []);
0 голосов
/ 01 ноября 2019

Если я понимаю, что вы спрашиваете, это:

Вы хотели бы установить флаги для пустого массива без необходимости добавлять предыдущие значения, используя метод распространения, которыйв настоящее время вы делаете {...state, flags: []}.

Что ж, это невозможно при использовании useState, и вы должны быть осторожны с вложенными объектами состояния, поскольку клонирование может стать дорогостоящим с более крупными объектами. Может быть, это то, чего вы пытаетесь избежать здесь .

Даже если вы переключитесь на useReducer, вы все равно в конечном итоге распределяете опору для штата.

Возможно, вам следуетпросто укажите в качестве своего собственного флага const [flags, setFlags] = useState([]) или посмотрите на immutable-helper .

Более того, попробуйте уважать react-hooks/exhaustive-deps других жен, могут начаться забавные вещи. Если нет deps, то, по крайней мере, дайте вашему хуку пустой массив, чтобы убедиться, что он выполняется один раз.

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