首页 > 解决方案 > 变量在 Fetch 中改变但在函数之外没有改变

问题描述

我有一个 React App,我有一个 App 容器,我想在其中调用 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。返回正确的值后,我希望将它们作为道具传递给组件。

非常感谢!

标签: javascriptreactjstypescriptfetch-api

解决方案


部分问题是您似乎没有正确区分同步和异步代码。fetch是异步的,这意味着不能保证该代码在文件中的任何其他内容之前运行。(fetch使用 JS promises 来管理异步数据,所以它有助于很好地掌握使用 promises。)

在典型的 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 和通用 JS 概念你需要确保你掌握,特别是在状态和异步数据获取方面。不确定到目前为止你有多少经验,但你可能想看看一些介绍教程(可能像这个官方教程),看看你可以遵循多少,是否有任何东西可以作为你的东西跳出来需要熟悉更多。


推荐阅读