Отмена Asyn c useEffect с TypeScript, правильный путь - PullRequest
1 голос
/ 03 марта 2020

У меня есть простой пример, который меня огорчает:

useEffect(() => {
  axios.get(...).then(...).catch(...)

}, [props.foo])

предупреждение: не удается выполнить обновление состояния реагирования на отключенном компоненте

Готово исследование и это более понятно. TypeScript, похоже, не нравится такой подход, поскольку useEffect должен возвращать пустоту.

useEffect(() => {
  let isSubscribed = true

  axios.get(...).then(...).catch(...)

  return () => (isSubscribed = false)

}, [props.foo])

TypeScript:

/**
     * Accepts a function that contains imperative, possibly effectful code.
     *
     * @param effect Imperative function that can return a cleanup function
     * @param deps If present, effect will only activate if the values in the list change.
     *
     * @version 16.8.0
     * @see https://reactjs.org/docs/hooks-reference.html#useeffect
     */
    function useEffect(effect: EffectCallback, deps?: DependencyList): void;

Как реализовать isSubscribed в мой useEffect с TS?

спасибо.

1 Ответ

0 голосов
/ 03 марта 2020

useEffect само возвращает void, но функция, предоставленная для useEffect, набирается как EffectCallback. Это определяется как:

// NOTE: callbacks are _only_ allowed to return either void, or a destructor.
// The destructor is itself only allowed to return void.
type EffectCallback = () => (void | (() => void | undefined));

Источник

Это означает, что ваш обратный вызов эффекта может фактически возвращать функцию, которая должна возвращать void или undefined.

Теперь вы можете решить свою проблему, чтобы избежать вызова setState с переменной isSubscribed. Но другой (возможно, лучший) способ состоит в прямой отмене запроса.

useEffect(() => {
  const CancelToken = axios.CancelToken;
  const source = CancelToken.source();

  axios.get('...', { cancelToken: source.token }).then(/**/).catch(e => {
    if (axios.isCancel(thrown)) {
      console.log('Request canceled', thrown.message);
    } else {/* handle error */}
  });

  return () => source.cancel();
}, [props.foo])

Это также задокументировано в README .

Проблема с вашим текущим кодом , что ваша деструкторная функция возвращает логическое значение isSubscribed. Вместо того, чтобы возвращать его, просто поместите присвоение в тело функции:

return () => {
  isSubscribed = false;
}
...