如何将setTimeout()与React Hooks useEffect和setState一起使用?

时间:2020-04-20 10:26:36

标签: javascript reactjs react-hooks settimeout use-effect

我想等待10秒钟,以便我的API调用从后端获取类别列表数组并存储在挂钩状态。如果10秒之内没有任何获取,我想将错误挂钩状态设置为true。

但是问题是,甚至在最初获取数组之后,错误状态仍设置为true,状态为categoryList的数组在10秒后消失。

import React, { useState, useEffect } from "react";

import { doGetAllCategories } from "../helper/adminapicall.js";

const ViewCategories = () => {
  let [values, setValues] = useState({
    categoriesList: "",
    error: false,
  });

  let { categoriesList, error } = values;

  const preloadCategories = () => {
    doGetAllCategories()
      .then((data) => {
        if (data.error) {
          return console.log("from preload call data - ", data.error);
        }
        setValues({ ...values, categoriesList: data.categories });
      })
      .catch((err) => {
        console.log("from preload - ", err);
      });
  };

  useEffect(() => {
    preloadCategories();

    let timerFunc = setTimeout(() => {
      if (!categoriesList && !error) {
        setValues({
          ...values,
          error: "Error fetching category list... try after some time !",
        });
      }
    }, 10000);

    return () => {
      clearTimeout(timerFunc);
    };
  }, []);



//...further code

2 个答案:

答案 0 :(得分:1)

问题在于useEffect回调是categoriesList的闭包,因此您将始终在回调中看到初始类别列表,并且看不到对其的任何更改。现在,可以将categoriesList作为对useEffect钩子的依赖,这样,将在每次categoriesList更改时重新创建该钩子,因此您可以看到更改后的版本:

useEffect(/*...*/, [categoriesList]);

现在的好处是,通过更新挂钩,超时也被取消了,因此,如果设置了类别列表,我们就不必创建新的超时了:

  useEffect(() => {
    if(!categoriesList && !error) {
      let timerFunc = setTimeout(() => {
        setValues({
          ...values,
          error: "Error fetching category list... try after some time !",
        });
      }, 10000);

      return () => clearTimeout(timerFunc);
  }
}, [!categoriesList, !error]); // some minor optimization, changes to the list don't bother this hook

我建议您阅读this blog post on useEffect by Dan Abramov

答案 1 :(得分:0)

您的代码存在问题,因为您希望在useEffect挂钩内更改组件的状态。而是在useEffect内创建两个变量,以跟踪是否已超过10秒的限制或已获取数据。与状态变量相反,您可以预期这些变量会发生变化,因为它们位于相同的useEffect中。

export default function App() {
  const [data, setData] = React.useState(null);
  const [error, setError] = React.useState(null);
  React.useEffect(() => {
    let didCancel = false;
    let finished = false;
    async function fetchData() {
      const data = await subscribeAPI();
      if (!didCancel) {
        finished = true;
        setData(data);
      }
    }
    const id = setTimeout(() => {
      didCancel = true;
      if (!finished) {
        setError("Errorrrr");
      }
    }, 10000);

    fetchData();

    return () => {
      clearTimeout(id);
    };
  }, []);