在 React 中与 JS Promises 作斗争

Posted

技术标签:

【中文标题】在 React 中与 JS Promises 作斗争【英文标题】:Struggling With JS Promises in React 【发布时间】:2021-01-15 20:26:27 【问题描述】:

我正在为 javascript 中的 Promise 概念而苦苦挣扎。我正在编写一个 React 应用程序,它使 GET 调用 Java 中的单独 API 服务,我想将其状态存储在 useState() 挂钩中。所以这是我的fetch 代码:

const ratingsUrl = "%URL%";
const base64 = require("base-64");
const login = "login";
const password = "password";

function fetchRatings() 
  return fetch(ratingsUrl, 
    method: "GET",
    headers: new Headers(
      Authorization: "Basic " + base64.encode(login + ":" + password),
    ),
  )
    .then((response) => response.json())
    .catch(handleError);

现在我正在尝试将其状态存储在我的页面组件中的挂钩中:

function DisplayPage()
  const [ratings, setRatings] = useState(fetchRatings());

.
.
.

现在,数据返回,但它位于 Promise 中,因此导致错误:

Promise <pending>
__proto__: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: Array(20)

我需要做的是在一个钩子中初始化数据并在Table 中返回它,这样我就可以映射它。但是,每当我尝试做类似的事情时

ratings.map()

我在控制台中收到一个 TypeError 提示 ratings.Map is not a function

我知道fetch 库异步返回数据,但我真正想要的只是将PromiseResult 存储在useState() 钩子中,这样我就可以进一步对其执行操作。

【问题讨论】:

fetchRatings 返回一个 Promise ...使用您已经知道的 Promise 方法来获得承诺的价值(即您需要使用 .then 【参考方案1】:

由于 fetch 是异步运行的,因此您将无法使用调用 fetchRatings 的即时结果来初始化您的状态。

幸运的是,有几种相当简单的方法可以处理这个问题。您可以使用空值初始化您的状态,然后在 fetchResults 解析后更新它:

function DisplayPage() 
  // initially ratings will be undefined
  const [ratings, setRatings] = useState();

  // update state when fetchResults comes back
  fetchResults().then(response => setRatings(response));

  // ...

为了便于阅读,上面的示例省略了这一点,但您通常会通过useEffect 执行此操作,因此它会在您的组件安装或相关输入(通常是道具,称为效果的依赖项)发生更改时运行:

function DisplayPage() 
  const [ratings, setRatings] = useState();

  useEffect(() => 
    fetchResults().then(response => setRatings(response));
  , []) // empty dependencies array will cause the effect to run only once, on mount

  // ...

【讨论】:

【参考方案2】:

我建议使用 useEffect 挂钩来设置初始状态。(类似于 componentDidMount)

因此,如果您期望的响应是例如一个数组。

const [ratings, setRatings] = useState([]);

然后在 useEffect 挂钩中,当您从获取请求中获得响应时更新状态。 这样,如果您在请求完成之前在 DOM 中的某处映射评级,则可以防止错误。

useEffect()
    fetch(ratingsUrl, 
        method: "GET",
        headers: new Headers(
            Authorization: "Basic " + base64.encode(login + ":" + password),
        ),
    )
    .then((response) => 
         response.json()
    )
    .then(res => setRatings(res))
    .catch(handleError);

【讨论】:

【参考方案3】:

这个怎么样,

const [ratings, setRatings] =  useState();
useEffect(()=>
         fetch(ratingsUrl, 
method: "GET",
headers: new Headers(
  Authorization: "Basic " + base64.encode(login + ":" + password),
)).then((response) => let res = response.json();
    setRatings(res)
      )
.catch(handleError);
 ,[])

【讨论】:

【参考方案4】:

async 方法返回承诺。如果你直接在你的setRatings状态变量中设置一个promise的结果,你会得到一个promise。

通常会这样重写:

function DisplayPage()
  const [ratings, setRatings] = useState(null);

  useEffect(() => 

    fetchRatings
      .then(result => setRatings(result))
      .catch(err => console.error(err));

  , []);
 
  if (ratings === null) return <div>loading...</div>;
  
  /* .. do your thing .. */


【讨论】:

谢谢,它解决了一些最初的错误——但是,当我想返回一个 Table 并映射到之前实例化的 ratings 对象时,我仍然得到一个 ratings.Map不是函数... 1.当评级仍然为null 时返回加载程序是必要的,就像我在我的示例中所做的那样。 2. 如果 ratings 是一个数组,你可能在寻找 .map 函数,而不是 .Map 函数。

以上是关于在 React 中与 JS Promises 作斗争的主要内容,如果未能解决你的问题,请参考以下文章

javascript 在系列#js #promise中运行Promises

javascript 在系列#js #promise中运行Promises

Node.js、Promises & Recursion - 可能吗?

在Node JS中使用promises

澄清 node.js + promises 片段

Node.js:何时使用 Promises 与 Callbacks