我正在尝试了解React Hooks,并发现了一个问题。我想获取数据,先显示30个条目,然后在后台获取其余数据。 我的逻辑:
useEffect(() => {
(async function () {
setIsLoading(true);
try {
const data = sortById(await fetch('url'));
const prep = await prepareData(data, (pageNumber - 1) * elementsPerPage, pageNumber * elementsPerPage);
setData(prep);
setIsLoading(false);
const backgroundData = await fetchMissingData(prep, elementsPerPage)
setData(backgroundData);
} catch (e) {
setError(e);
setIsLoading(false);
}
})();
}, [])
data
是来自API的响应,然后我使用它向prepareData中的对象添加了一些内容-该对象本身正在调用另一个API,因此当所有请求完成时
return Promise.all(result).then(done => {
return done;
})
我正在获取对象数组,但是只有前30个对象充满了我需要的数据。准备好数据后,我将状态data
设置为loading
并设置为false。在那一刻,数据应该在页面上呈现(?)。然后,我将在后台获取其余数据,而无需再次获取相同的数据(前30个条目),并为我在应用程序中需要的每个条目再次设置data
。
问题在于,数据是在上一个setData
之后呈现的-应用程序正在等待每个提取完成。
我的逻辑错误在哪里?
答案 0 :(得分:1)
setState
,就像在类组件中一样,它是一个异步调用(它不会立即起作用,但会告诉组件应使用不同的上下文再次呈现它)。
例如,--
useEffect(() => {
(async function () {
setIsLoading(true);
try {
setIsLoading(false);
...
} catch (e) {
setError(e);
setIsLoading(false);
}
})();
}, [])
isLoading
永远不会在其组件中成为true
,导致您同时给它true
和false
(假设您的代码可以逐行工作,不能保证使用JS,您可能会遇到副作用)。
data
遇到了同样的事情,因为您两次致电setData
因此,您可以考虑将效果分成两个效果,而isLoading
是第二个效果要运行的标志
useEffect(() => {
(async function () {
setIsLoading(true);
try {
const data = sortById(await fetch('url'));
const prep = await prepareData(data, (pageNumber - 1) * elementsPerPage, pageNumber * elementsPerPage);
setData(prep);
} catch (e) {
setError(e);
setIsLoading(false);
// in case there is e at first effect,second effect wont run
}
})();
}, [])
useEffect(() => {
if (isLoading) {
(async function () {
try {
//data now is equal to prep
const backgroundData = await fetchMissingData(data, elementsPerPage)
setData(backgroundData);
} catch (e) {
setError(e);
}
})();
setIsLoading(false);
}
}, [isLoading, data])
如果isLoading
标志已经用于UI渲染或其他用途,并且不能作为第二效果的标志,则可以创建唯一的isSecondEffectShouldRun
或类似的方法(使用{{1} }本身将导致无限循环...)
希望它会有所帮助:)