在 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