如何将 setTimeout() 与 React Hooks useEffect 和 setState 一起使用?
How to use setTimeout() along with React Hooks useEffect and setState?
我想等待 10 秒,以便我的 API 调用从后端获取类别列表数组并存储在挂钩状态。如果 10 秒内未获取任何内容,我想将错误挂钩状态设置为 true。
但问题是即使在最初获取数组后,错误状态设置为 true 并且状态中的 categoriesList 数组在 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
问题在于 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
您的代码存在问题,您希望在 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);
};
}, []);
我想等待 10 秒,以便我的 API 调用从后端获取类别列表数组并存储在挂钩状态。如果 10 秒内未获取任何内容,我想将错误挂钩状态设置为 true。
但问题是即使在最初获取数组后,错误状态设置为 true 并且状态中的 categoriesList 数组在 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
问题在于 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
您的代码存在问题,您希望在 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);
};
}, []);