我正在使用REACT挂钩组件,该组件使用Fetch API来获取数据fetch
。虽然,我面临的一个问题是我不确定如何解决这个问题,或者更好地说,我不确定是否有任何“推荐”的方式来解决此问题。
以下面的代码为例:
const Fetcher = () => {
[data, setData] = useState([]);
const handleButtonClick = (e) => {
fetch('http://www.myapi.com')
.then(response => response.json())
.then(json => {
const newData = [...data];
newData.push(json);
setData(newData);
});
}
return <button onClick={handleButtonClick}>Click to fetch</button>
}
这不是一个可行的示例,但是很清楚发生了什么:我单击一个按钮,然后获取东西;某些东西已添加到当前状态。
现在,问题出在哪里?当我写文章时,const newData = [...data]
我考虑的data
是fetch
启动时可用的变量,而不是当前的变量data
。这意味着,如果fetch
要花1分钟执行时间,那么在那一刻data
可能会以其他方式进行更新,因此,在fetch.then().then()
调用时,我会data
用不正确的值覆盖实际电流。
我可以给您这个方案,以使您更好地理解:
fetch
执行data
等于[ ]
;fetch
结尾之前再次单击(再次data
等于[ ]
;data
保存新值(例如['foo']
);data
是一个空数组,因此将其保存在data
数组中['bar']
;如您所见,在一天结束时,我有一个数组['bar']
,而应该是['foo', 'bar']
。
针对此问题,我提出了两种解决方案:
将状态副本保存在中ref
,并在中使用它fetch.then().then()
。像这样:
const Fetcher = () => {
[data, setData] = useState([]);
const refData = useRef(data);
const handleButtonClick = (e) => {
fetch('http://www.myapi.com')
.then(response => response.json())
.then(json => {
const newData = [...refData.current];
newData.push(json);
setData(newData);
});
}
useEffect(() => {
refData.current = data;
}, [data]);
return <button onClick={handleButtonClick}>Click to fetch</button>
}
使用一个临时变量和一个useEffect来处理最新的变量:
const Fetcher = () => {
[data, setData] = useState([]);
[lastFetchedData, setLastFetchedData] = useState();
const handleButtonClick = (e) => {
fetch('http://www.myapi.com')
.then(response => response.json())
.then(json => {
setLastFetchedData(json);
});
}
useEffect(() => {
const newData = [...data];
newData.push(lastFetchedData);
setData(newData);
}, [lastFetchedData]);
return <button onClick={handleButtonClick}>Click to fetch</button>
}
我很确定他们两个都可以正常工作而不会造成任何重大问题,但是:
第一种方法:我不知道,在我看来这与REACT思维方式背道而驰。我正在使用ref来保持某个地方的最新状态。我的意思是,我不知道这对于REACT“生活方式”是否可行;
第二种方法:在这种情况下,我仅使用状态。我在这里不喜欢的是,每当获取一些数据时,我都会做一个额外的渲染。没什么大不了的,但是,如果可以避免,那就更好了。如果lastFetchedData
不是null
,我可以返回一个空白页,但用户可能会在毫秒内看到该空白页。实际上,它不会看到空白页面,但是由于两个渲染,页面可能会闪烁;
通常的解决方案是使用以下回调形式setData
:
const Fetcher = () => {
[data, setData] = useState([]);
const handleButtonClick = (e) => {
fetch('http://www.myapi.com')
.then(response => response.json())
.then(json => {
setData(data => [...data, json]); // <============
});
}
return <button onClick={handleButtonClick}>Click to fetch</button>
}
旁注:
你的代码是堕入中footgunfetch
我描述API在这里。您需要response.ok
在致电之前进行检查json
。
您没有处理来自的错误fetch
。
您忘了声明data
和setData
(我建议使用严格模式,所以这是一个错误):
所以:
const Fetcher = () => {
const [data, setData] = useState([]);
// ^^^^^−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− #3
const handleButtonClick = (e) => {
fetch('http://www.myapi.com')
.then(response => {
if (!response.ok) { // #1
throw new Error("HTTP error " + response.status); // #1
} // #1
return response.json();
})
.then(json => {
setData(data => [...data, json]);
})
.catch(error => { // #2
// Handle/report error here // #2
}); // #2
}
return <button onClick={handleButtonClick}>Click to fetch</button>
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句