为什么这多次触发fetchData
? console.log
似乎几乎无限循环吗?如何使它仅在加载时运行一次并在以后调用fetchData()
时仅触发一次?我在这里做错了什么或想念什么?
const [data, setData] = useState(null);
let fetchData = React.useCallback(async () => {
const result = await fetch(`api/data/get`);
const body = await result.json();
setData(body);
console.log(data)
},[data])
useEffect(() => {
fetchData();
},[fetchData]);
更新(其他问题):如何在data
之前等待return()
填充,下面的内容由于最初为空而出现错误?data.map is not a function
return (
<select>
{data.map((value, index) => {
return <option key={index}>{value}</option>
})}
</select>
)
答案 0 :(得分:4)
在useCallback
钩子中,您将data
作为依赖项进行传递,并且还通过调用setData
同时在回调内部更改数据值,这意味着每次数据值更改{ {1}}将被重新初始化。
在fetchData
钩子useEffect
中是一个依赖项,这意味着每次fetchData
的更改fetchData
都会被触发。这就是为什么出现无限循环的原因。
因为要在安装组件时一次获取数据,所以我认为这里useEffect
是不必要的。无需不必要地记住函数useCallback
。
解决方案
fetchData
如果要记录const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const result = await fetch(`api/data/get`);
const body = await result.json();
setData(body);
} catch(err) {
// error handling code
}
}
// call the async fetchData function
fetchData()
}, [])
的值更改时的值,则可以使用另一个data
来记录。例如,
useEffect
P.S。 -同样不要让诺言无法兑现,请使用useEffect(() => {
console.log(data)
}, [data])
块来处理错误。我已经更新了解决方案,使其包括try..catch块。
编辑- 其他问题的解决方案 有两种可能的解决方案,
由于您期望try...catch
的值是API调用后的数组,因此您可以将data的值初始化为一个空数组,例如,
data
但是,如果由于某种原因,您必须将const [data, setData] = useState([]);
的值初始化为data
。这是呈现您从API调用返回的信息的方法。
null
请勿将// using short-circuit evaluation
return (
<select>
{data && data.length && data.map((value) => {
return <option key={`select-option-${value}`}>{value}</option>
})}
</select>
)
// using a ternary
return (
<div>
{ data && data.length
? (<select>
{
data.map(value => <option key={`select-option-${value}`}>{value}</option>)
}
</select>
)
: <div>Data is still loading...</div>
}
</div>
)
用作indexes
,请使用唯一的密钥。