使用TypeScript取消useEffect的Async,正确的方法

时间:2020-03-03 11:31:29

标签: javascript reactjs typescript use-effect

我有一个让我感到悲伤的简单示例:

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

}, [props.foo])

警告:无法在未安装的组件上执行反应状态更新

做了一些研究,this one更容易理解。 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;

如何通过TS在我的isSubscribed中实现useEffect

谢谢。

1 个答案:

答案 0 :(得分:0)

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

Source

这意味着您的效果回调实际上可以返回一个函数,该函数必须返回voidundefined

现在,您可以解决问题,避免使用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;
}