将 Promise 分配给 React 中的变量
Assign Promise To Variable In React
总的来说,我对 JavaScript/React 很陌生,对 Promise
和 async
的概念感到困惑。
首先我有 getSimById
,一个在 JS 文件中的 API 调用,其中 returns 一个 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.");
}
现在我有一个功能组件 returns a 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]
之类的内容时,它实际上是 returns undefined
,并且我无法在 Table
中映射它的值。在这种情况下,如何将 Promise 分配给一个变量,以便我可以对其执行操作?
在您的 useEffect
中,您已经在调用 getSimById()
并存储结果,因此无需立即再次调用它。
相反,请尝试遍历 simResult
数组。那应该具有您要引用的值。
你不应该在两个不同的地方调用 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>
);
}
还有另一个问题:如果您的效果在到达之前再次 运行,您希望忽略异步获得的结果。为此,您 return 来自 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, market) =>
market.selections.map(({ name, probability }, index) => ({
...accumulator[index],
"Team name": name,
[market.name]: probability,
})),
[],
) : 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 通话正常,您收到
useEffect(() => {
getSimById(location.state.simId).then(result => setSimResult(result));
}, []);
同时解析数据可以这样简化
getSimById(location.state.simId).then(parseSimResult);
但是你的问题出在let
这里。
可能的解决方案是:
超出组件(可能是实用程序)?
export const parseSimResults = (simResults) => {
return simResults.markets.reduce(
(accumulator, market) =>
market.selections.map(({ name, probability }, index) => ({
...accumulator[index],
"Team name": name,
[market.name]: probability,
})),
[],
)
};
然后就在渲染图中抛出 simResults
在你的组件渲染中
<thead>
{simResult && simResults.map(r => {
<tr key="someKEY">
{
...
}
</tr>
})}
</thead>
生成完整代码
const parseSimResults = (simResults) => {
return simResults.markets.reduce(
(accumulator, market) =>
market.selections.map(({ name, probability }, index) => ({
...accumulator[index],
"Team name": name,
[market.name]: probability,
})),
[],
)
};
const MyComponent.... {
const [simResults, setSimResults] = useState([]);
useEffect(() => {
getSimById(location.state.simId).then(parseSimResults);
}, []);
return simResults.map(r => <your JSX>)
}
总的来说,我对 JavaScript/React 很陌生,对 Promise
和 async
的概念感到困惑。
首先我有 getSimById
,一个在 JS 文件中的 API 调用,其中 returns 一个 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.");
}
现在我有一个功能组件 returns a 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]
之类的内容时,它实际上是 returns undefined
,并且我无法在 Table
中映射它的值。在这种情况下,如何将 Promise 分配给一个变量,以便我可以对其执行操作?
在您的 useEffect
中,您已经在调用 getSimById()
并存储结果,因此无需立即再次调用它。
相反,请尝试遍历 simResult
数组。那应该具有您要引用的值。
你不应该在两个不同的地方调用 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>
);
}
还有另一个问题:如果您的效果在到达之前再次 运行,您希望忽略异步获得的结果。为此,您 return 来自 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, market) =>
market.selections.map(({ name, probability }, index) => ({
...accumulator[index],
"Team name": name,
[market.name]: probability,
})),
[],
) : 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 通话正常,您收到
useEffect(() => {
getSimById(location.state.simId).then(result => setSimResult(result));
}, []);
同时解析数据可以这样简化
getSimById(location.state.simId).then(parseSimResult);
但是你的问题出在let
这里。
可能的解决方案是:
超出组件(可能是实用程序)?
export const parseSimResults = (simResults) => {
return simResults.markets.reduce(
(accumulator, market) =>
market.selections.map(({ name, probability }, index) => ({
...accumulator[index],
"Team name": name,
[market.name]: probability,
})),
[],
)
};
然后就在渲染图中抛出 simResults
在你的组件渲染中
<thead>
{simResult && simResults.map(r => {
<tr key="someKEY">
{
...
}
</tr>
})}
</thead>
生成完整代码
const parseSimResults = (simResults) => {
return simResults.markets.reduce(
(accumulator, market) =>
market.selections.map(({ name, probability }, index) => ({
...accumulator[index],
"Team name": name,
[market.name]: probability,
})),
[],
)
};
const MyComponent.... {
const [simResults, setSimResults] = useState([]);
useEffect(() => {
getSimById(location.state.simId).then(parseSimResults);
}, []);
return simResults.map(r => <your JSX>)
}