【发布时间】:2020-05-20 18:20:02
【问题描述】:
我正在开发一个使用 Fetch API fetch 获取数据的 REACT 钩子组件。虽然,我面临一个我不太确定如何解决的问题,或者更好地说,我不确定是否有任何“推荐”的方式来解决这个问题。
以这段代码为例:
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] 时,我考虑的是fetch 启动时可用的data 变量,而不是当前的data。这意味着,如果 fetch 需要 1 分钟才能执行,那么在那一分钟内 data 可能会以其他方式更新,因此,当调用 fetch.then().then() 时,我会覆盖实际当前的 data一些不正确的东西。
我可以给你这个方案,让你更好地理解:
- 我单击并执行第一个
fetch,data等于[ ]; - 我在第一个
fetch结束前再次单击(同样,data等于[ ]; - 第二次提取结束并在
data中保存新值(例如['foo']); - 第一次提取结束接收'bar'。由于它使用的是空数组
data,因此将数组['bar']保存在data中;
如您所见,归根结底,我有一个数组['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,我可以返回一个空页面,但用户可能会看到该空页面一毫秒。实际上,它不会看到空白页面,但可能由于两次渲染导致页面闪烁;
【问题讨论】:
标签: javascript reactjs react-hooks