useEffects 中的异步 API 调用和更新 useState

时间:2021-03-31 21:23:25

标签: javascript reactjs axios react-hooks

我有下面的代码

const [status, statusSetter] = useState({ isAuthenticated: false });

useEffect(() => {
    let didCancel = false;
    
    async function fetchMyAPI() {
        if (!didCancel) {
            let response = (await axios.get('api/auth/getuserstatus')).data;

            statusSetter(response);

        }
        
    }

    fetchMyAPI();

    return () => {
        didCancel = true;
    }
    }, []);

我尝试将 didcancel 实现为 userEffects 的一种清理形式,但它不起作用。我收到以下错误: “无法对卸载的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。” 我应该把什么东西清理干净?

3 个答案:

答案 0 :(得分:1)

那个变量应该只阻止调用 statusSetter:

async function fetchMyAPI() {
        let response = (await axios.get('api/auth/getuserstatus')).data;
        !didCancel && statusSetter(response);       
}

但是,基本上,这是一个黑客,因为这种方法不会清理任何东西。我们保留无用的后台工作,只是不更改结果中的组件状态。我们应该以某种方式中止挂起的 get 请求。

通过自定义的实验性钩子,我们可以编写可自动取消的异步例程。例如,如果在获取 (Live demo to play) 时卸载组件,则以下 json 请求将自动中止:

import React, { useState } from "react";
import { useAsyncEffect, E_REASON_UNMOUNTED } from "use-async-effect2";
import cpAxios from "cp-axios";

export default function TestComponent(props) {
  const [text, setText] = useState("");

  const cancel = useAsyncEffect(function* () {
        const response = yield cpAxios(props.url);
        setText(`Success: ${JSON.stringify(response.data)}`);
    },
    [props.url]
  );

  return (...)
}

答案 1 :(得分:0)

此代码应该适合您:

WITH product_ids AS (
    WITH RECURSIVE cte AS (
       (   -- parentheses required
           SELECT product_id
           FROM tickers
           ORDER BY 1
           LIMIT 1
       )
       UNION ALL
       SELECT l.*
       FROM cte c
       CROSS JOIN LATERAL (
          SELECT product_id
          FROM tickers t
          WHERE t.product_id > c.product_id  -- lateral reference
          ORDER BY 1
          LIMIT 1
          ) l
       )
    TABLE cte
)
SELECT
    product_id,
    (SELECT (MAX(trade_id) - MIN(trade_id) + 1) FROM tickers WHERE product_id = product_ids.product_id) AS ticker_count,
    (SELECT MIN(time) FROM tickers WHERE product_id = product_ids.product_id) AS min_time,
    (SELECT MAX(time) FROM tickers WHERE product_id = product_ids.product_id) AS max_time
FROM product_ids
ORDER BY ticker_count DESC

答案 2 :(得分:0)

使用 axios,您可以这样做:

  useEffect(() => {
    const source = axios.CancelToken.source();
    fetchMyAPI(source);
    return () => {
      source.cancel();
    };
  }, []);

然后在获取函数中

const fetchMyAPI = async (source) => {
    try {
      const response = await axios({
        cancelToken: source.token,
      });
    } catch (err) {
      if (!axios.isCancel(err)) {
         // TO DO...
      }
    }
  };