React在useeffect内同时设置2个状态



我有一个组件,我用它来显示数据条目的列表,像这样(简化):

// resource is the rest endpoint, 
// items is the parents components 
// state that holds the data entries and setItems is the corresponding setter
export default function LoadedList({resource,items, setItems,CustomFormat}){
const [loadingOrError,setLoadingOrError] =useState(false)
useEffect(()=>{
axios.get(baseURL+resource)
.then((e)=>{
setItems(e.data)
setLoadingOrError(false)
})
.catch((e)=>{
setItems([{text:"Error"}])
setLoadingOrError(true)
})
setItems([{text:"Loading...-"}])
setLoadingOrError(true)
},[])

return(
<div className="list">
{
items.map((item)=>
loadingOrError?
<DefaultFormat item={item} />
:
<CustomFormat item={item}/>
)
}
</div>
)
}

基本思想是,当组件加载项或失败时,应该使用默认格式来显示相应的消息。一旦条目成功加载,应该使用来自父条目的格式来格式化条目。问题是,我发现settitems和setLoading没有同时改变。它的工作方式是,它首先设置items,然后呈现所有条目,然后才将loadingOrError更改为true。有没有办法同时设置这两个呢?或者只是不重新渲染中间的所有内容?

与其尝试同时更新两者,不如尝试分别跟踪加载和错误状态,然后做如下操作:

// resource is the rest endpoint, 
// items is the parents components 
// state that holds the data entries and setItems is the corresponding setter
export default function LoadedList({resource, items, setItems, CustomFormat}){
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
useEffect(()=>{
setLoading(true);
axios.get(baseURL+resource)
.then((e)=>
setItems(e.data)
)
.catch((e)=>
setError("Error")
)
.finally(() => setLoading(false));
},[])
if(loading) {
return "Loading ...";
}
if(error) {
return error;
}   
return(
<div className="list">
{items.map((item, index) => <CustomFormat key={index} item={item}/>)}
</div>
)
}

显示Loading...,直到所有的项目都被加载。

如果你坚持想让一切保持原样,并且只是实现你最初要求的同时更新,你可能需要定义一个函数来执行API调用,连同加载状态,错误状态和数据状态处理,将所有这些状态一起放在同一个状态钩子下,然后传递API函数在子的useEffect中使用。

const [dataState, setDataState] = useState({
data: null,
loading: false,
error: ""
});
...
setDataState({data: data, loading: false});

除此之外,我推荐两件事:

  • 在设置状态之前,当请求完成时,您应该检查组件是否仍然挂载。否则你会得到一个错误。这是非常容易实现的,使用一个额外的变量来跟踪挂载状态。创建一个自定义钩子来处理请求可能是有益的,因为这可能是你会经常做的事情,而且它在每种情况下看起来都很相似。我发现这篇文章中的分步指南非常清晰。

摘自那篇文章:

useFetch自定义钩子

import { useState, useEffect } from 'react';
const useFetch = (url = '', options = null) => {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
let isMounted = true;
setLoading(true);
fetch(url, options)
.then(res => res.json())
.then(data => {
if (isMounted) {
setData(data);
setError(null);
}
})
.catch(error => {
if (isMounted) {
setError(error);
setData(null);
}
})
.finally(() => isMounted && setLoading(false));
return () => (isMounted = false);
}, [url, options]);
return { loading, error, data };
};
export default useFetch;

相关内容

  • 没有找到相关文章

最新更新