javascript - 在 Fetch 中变量被修改但在函数外未改变
我有一个 React 应用程序,我有一个应用容器,我想在其中调用 fetch 来获取一些数据,以便传递给需要这些信息的组件。
我在 onload 函数外部(我的 fetch 所在的位置)声明了变量,并在 fetch 中给它们赋了不同的值。变量在 fetch 中会改变,但在 fetch 外部它们保持不变。
为什么它们不会保持更改,有没有办法解决这个问题?
我尝试过将用 var 声明的变量改为 let,也尝试过将函数放在 const 里面。
我也尝试过将 fetch 放在其他组件中(比如下面看到的 Table),但是那样我就必须声明两个状态并在 fetch 内部调用另一个 fetch,因为我已经在那里调用了另一个 fetch,这变得很麻烦……
let latestRelease = 0;
let draftRelease = 0;
let doClone = false;
function onload() {
fetch(url, {
method: 'GET'
})
.then(function(response) {
return response.json();
})
.then(function(result) {
for(var i = 0; i < result.length; i++)
{
if(result[i].id > latestRelease && result[i].status === "released") {
latestRelease = result[i].id;
}
if(result[i].id > draftRelease && result[i].status === "draft") {
draftRelease = result[i].id;
}
}
if(latestRelease > draftRelease) {
doClone = true;
}
})
.catch((error) => {
console.log(error);
});
}
const App: React.FC = () => {
onload()
return (
<React.Fragment>
<CssBaseline />
<Container fixed>
<PersistentDrawerLeft/>
{console.log(latestRelease)} //displays 0
<Title/>
<Table />
</Container>
</React.Fragment>
);
}
export default App;
我期望 latestRelease 和 draftRelease 不保持为 0,而是大于 0 的任何值,但输出只是 0。在返回正确值后,我希望将它们作为属性传递给组件。
非常感谢!
答案#1
问题的一部分是你似乎没有正确区分同步和异步代码。fetch 是异步的,这意味着该代码不能保证在文件中的其他任何代码之前运行。(fetch 使用 JS promise 来管理异步数据,因此掌握 promise 的使用会有帮助。)
在一个典型的 React 情况下,你会想做几件不同的事情。首先,你希望使用组件状态来保存数据,而不仅仅是随机变量(这允许 React 在这些值改变时重新渲染)。其次,当你异步获取数据时,你需要弄清楚在获取完成之前你的应用应该做什么。
这里有一个非常基础的例子,展示这可能如何工作:
import React, { useState, useEffect } from 'react'
const App = ({ url }) => {
// We'll use this variable to store an object with the details
const [releaseDetails, setReleaseDetails] = useState(null)
// When the component is loaded, we'll fetch the url (coming from the component props) and then
// run your logic.
useEffect(() => {
let latestRelease = 0;
let draftRelease = 0;
let doClone = false;
fetch(url)
.then((response) => response.json())
.then((result) => {
for(var i = 0; i < result.length; i++) {
if(result[i].id > latestRelease && result[i].status === "released") {
latestRelease = result[i].id;
}
if(result[i].id > draftRelease && result[i].status === "draft") {
draftRelease = result[i].id;
}
}
if(latestRelease > draftRelease) {
doClone = true;
}
// To make these details available to the component, we'll bundle them into an object
// and update the component's state:
setReleaseDetails({
latestRelease,
draftRelease,
doClone
})
})
.catch((error) => {
// You'd ideally want some proper error handling here
console.log(error)
});
}, []) // pass an empty array so this is only run when the component is first rendered
// Because we're getting the data asynchronously, we need to display something while we wait
if(releaseDetails === null) {
return "loading..."
}
// Once the data is available, you can then use the details when rendering. You could instead
// render a child component and pass the values as props to it.
return (
`LatestRelease: ${releaseDetails.latestRelease}`
)
}
一般来说,你可能需要确保自己掌握一些 React 和通用的 JavaScript 概念,特别是与状态和异步数据获取相关的部分。不太清楚你到目前为止有多少经验,但你可能想看看一些入门教程(可能像这个官方教程),看看你能跟上多少,以及是否有任何内容显得需要你进一步熟悉。
答案#2
你能试试用状态变量吗,因为如果状态变量改变,渲染会重新调用,这里你使用的是普通变量,可能它在改变,但不会重新渲染。
谢谢你。
