问题描述
我一般对JavaScript / React还是很陌生的,并且在Promise
和async
的概念中苦苦挣扎。
首先我有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);
}
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.");
}
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
数组。那应该具有您要引用的值。