在React中将Promise分配给变量

问题描述

我一般对JavaScript / React还是很陌生的,并且在Promiseasync的概念中苦苦挣扎。

首先我有getSimById,这是JS文件中的API调用,它返回了Promise

export function getSimById(simId) {
  return fetch(simsUrl + "/results/" + simId,{
    method: "GET",headers: new Headers({
      Authorization: "Basic " + base64.encode(login + ":" + password)
    })
  })
    .then(handleResponse)
    .catch(handleError);
}

handleResponse一个异步函数

export async function handleResponse(response) {
  if (response.ok) {
    let someResponse = response.json();
    return someResponse;
  }

  if (response.status === 400) {
    throw new Error(error);
  }

  const error = await response.text();
  throw new Error("Network response was not ok.");
}

现在我有一个返回Table功能组件:

import React,{ useState,useEffect } from "react";
import { getSimById } from "../apI/OutrightSimulatorApi";

function SimulationReport(props) {

  const location = useLocation();
  const [simResult,setSimResult] = useState([]);

  useEffect(() => {
    getSimById(location.state.simId).then(result => setSimResult(result));
  },[]);

  let reformattedData = getSimById(location.state.simId).then(
    data => reformattedData = data?.markets?.length ? data.markets.reduce(
      (accumulator,market) =>
        market.selections.map(({ name,probability },index) => ({
          ...accumulator[index],"Team name": name,[market.name]: probability,})),[],) : null);

  return (
      <div>
          <Table striped bordered hover size="sm" responsive>
            <thead>
              <tr>{

              }
              </tr>
            </thead>
            <tbody>{

             }
            </tbody>
          </Table>
      </div>
  );

在这代码中,我想将reformattedData映射为一个数组,并最终将其值映射到返回的Table中。但是,reformattedData在这种情况下不是数组,实际上是Promise。因此,每当我尝试访问类似reformattedData[0]之类的内容时,它实际上都会返回undefined,而我无法在Table中映射其值。在这种情况下,如何将Promise分配给变量,以便可以对其执行操作?

解决方法

您不应在两个不同的地方调用getSimById,而应仅在useEffect回调中,该回调应将location.state.simId列为依赖项。

遵循以下原则:

function SimulationReport(props) {

  const location = useLocation();
  const [simResult,setSimResult] = useState([]);

  useEffect(() => {
    getSimById(location.state.simId).then(data => {
        const reformattedData = data?.markets?.length ? data.markets.reduce(
          (accumulator,market) =>
            market.selections.map(({ name,probability },index) => ({
              ...accumulator[index],"Team name": name,[market.name]: probability,})),[],) : null;
        setSimResult(reformattedData); // *** Set state here
      })
      .catch(error => {
        // *** Handle/report error
      });
  },[location.state.simId]); // *** Note the dependency

  return (
      <div>
          <Table striped bordered hover size="sm" responsive>
            <thead>
              <tr>{

              }
              </tr>
            </thead>
            <tbody>{
              // *** Use `simResult` when rendering
              simResult.map(entry => <markup>for entry</markup)
             }
            </tbody>
          </Table>
      </div>
  );
}

还有另外一个难题:如果您在效果到达之前再次运行效果,则希望忽略异步获得的结果。为此,您可以从useEffect回调返回一个函数,以便React可以在发生时告诉您,就像这样:

  useEffect(() => {
    let cancelled = false; // ***
    getSimById(location.state.simId).then(data => {
        if (cancelled) {
            // Don't use it
            return;
        }
        const reformattedData = data?.markets?.length ? data.markets.reduce(
          (accumulator,) : null;
        setSimResult(reformattedData);
      })
      .catch(error => {
        // Handle/report error
      });
      return () => {        // *** A callback React will use when the effect runs again
        cancelled = true;   // *** Remember that *this* call has been cancelled
      };
  },[location.state.simId]);
丹·阿布拉莫夫(Dan Abramov)的

This article提供了一些有关钩子(尤其是useEffect)的出色信息。

,

好的,这样您的api调用就可以正常工作了,您会收到

KTable

可以像这样同时解析数据来简化

useEffect(() => {
    getSimById(location.state.simId).then(result => setSimResult(result));
  },[]);

但是您的问题出在这里getSimById(location.state.simId).then(parseSimResult);

可能的解决方案可能是:

超出组件范围(也许是utils)?

let

然后在渲染映射中将export const parseSimResults = (simResults) => { return simResults.markets.reduce( (accumulator,market) => market.selections.map(({ name,index) => ({ ...accumulator[index],) }; 投射到组件渲染中

simResults

产生的完整代码

<thead>
  {simResult && simResults.map(r => {
    <tr key="someKEY">
         {
          ...
         }
    </tr>
  })}
</thead>
,

在您的useEffect中,您已经在调用getSimById()并存储了结果,因此无需紧接着再次调用它。

相反,请尝试遍历simResult数组。那应该具有您要引用的值。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...