在反应中获取多个网址时无法更新钩子变量
Posted
技术标签:
【中文标题】在反应中获取多个网址时无法更新钩子变量【英文标题】:unable to update hooks variable when fetching multiple urls in react 【发布时间】:2021-03-31 02:18:05 【问题描述】:我正在尝试使用自定义反应挂钩存储来自 TMDB 电影 api 的数据。
useFetch.js
import React,useState,useEffect from 'react';
export default function useFetch()
const key = process.env.REACT_APP_API_KEY;
//the urls I want to get data from
const specificTypes = [
'Type':'Top Rated', 'url' :`https://api.themoviedb.org/3/movie/top_rated?api_key=$key`,
'Type':'Trending', 'url' :`https://api.themoviedb.org/3/trending/movie/day?api_key=$key`,
];
const [movieTypes,setMovieTypes] = useState([]); //this is where I want to store url data
useEffect(()=>
const fetchSpecificTypes = async ()=>
const promises = [];
specificTypes.map(async type=>
let response = await fetch(type.url);
let res = await response.json();
promises.push(res.results);
);
console.log(promises); data is stored in promises successfully
setMovieTypes(promises); //how I try to set the movies
fetchSpecificTypes();
,[]);
return movieTypes;
当我console.log(promises)
时,我得到这个对象,其中 2 项是电影类型,里面有 20 部电影:
然后当我尝试在另一个组件中显示来自上面对象的电影时:
MovieList.js
import React , useState,useEffect from 'react'
import useFetch from './useFetch';
import '../App.css';
export default function MovieList()
const movieTypes = useFetch();
const baseImgUrl = "https://image.tmdb.org/t/p";
const size = "/w400";
return (
<div className="movie-list">
movieTypes.map(movie=>
return (
<>
Object.values(movie).map((val,k)=>
let path = baseImgUrl + size + val.backdrop_path; //full image path
return <div className= "movie-item" key = val.id>
<img alt = "movie" src = path/>
<h4 className="movie-overview"> val.overview </h4>
<p className="movie-title">val.title</p>
</div>
)
</>
)
)
</div>
);
我什么也得不到,没有电影放映。非常感谢您的帮助。
【问题讨论】:
【参考方案1】:Await 在 Array.map() 中没有按预期工作。
您应该使用for
循环或使用Promise.all()
const fetchSpecificTypes = async() =>
const promises = [];
for(let i=0; i<specificTypes.length; i++)
let response = await fetch(specificTypes[i].url);
let res = await response.json();
promises.push(res.results);
setMovies(promises);
const fetchSpecificTypes = async() =>
const results = await Promise.all(specificTypes.map(type => fetch(type.url)));
const results2 = await Promise.all(results.map(res => res.json());
const movies = results2.map(res => res.results);
setMovies(movies);
【讨论】:
我刚刚添加了使用 Promise.all 的代码。 Wong 在你的例子中,我正确地获取了电影。现在我正在尝试显示它们 我使用了 Promise.all 方法,效果很好,谢谢!【参考方案2】:试试这个
useEffect(()=>
const fetchSpecificTypes = async ()=>
const promises=specificTypes.map(type=>fetch(type.url).then(res=>res.json()));
const response=await Promise.all(promises)
setMovies(response.flatMap(c=>c));
fetchSpecificTypes();
,[]);
【讨论】:
不起作用 TypeError: response[0].concat is not a function 我现在使用的示例与此不同。 代码已更新..请检查..如果它不起作用请告诉我 使用你下面的例子我设法得到了电影,现在我正试图正确地显示它们。非常感谢您抽出宝贵的时间。【参考方案3】:您没有从useFetch
收到任何值的原因(假设有要返回的值)是您返回结构 movies: [...]
但您读取了不存在的成员movieTypes
。
改变
const movieTypes = useFetch();
到
const movies: movieTypes = useFetch();
从 comp 外部的函数声明组件状态和效果对我来说看起来很可疑。无论是为了清晰还是为了功能,我认为最好在组件的顶层声明状态和任何效果。 (如果需要,可以拆分出效果的实现而不是声明以供重用。)例如,组合组件:
import React, useState, useEffect from 'react'
import '../App.css';
export default function MovieList()
const key = process.env.REACT_APP_API_KEY;
const specificTypes = [
'Type': 'Top Rated', 'url': `https://api.themoviedb.org/3/movie/top_rated?api_key=$key` ,
'Type': 'Trending', 'url': `https://api.themoviedb.org/3/trending/movie/day?api_key=$key` ,
];
const [movieTypes, setMovieTypes] = useState([]);
useEffect(() =>
const fetchSpecificTypes = async () => Promise.all(specificTypes.map(type => fetch(type.url)
.then(r => r.json())
.then(r => r.results)
)).then(results =>
console.log(results);
setMovieTypes([].concat(...results))
).catch(e => console.error(e));
fetchSpecificTypes();
, []);
const baseImgUrl = "https://image.tmdb.org/t/p";
const size = "/w400";
return (
<div className="movie-list">
movieTypes.map(movie =>
let path = baseImgUrl + size + movie.backdrop_path;
return <div className="movie-item" key=movie.id>
<img src=path />
<h4 className="movie-overview">movie.overview</h4>
<p className="movie-title">movie.title</p>
</div>
)
</div>
);
请注意,提取请求已被重组以传播承诺,而不是重复等待承诺。当所有 fetch promise 都解决时,数组被展平并设置状态变量。如果发生错误,则会报告。我没有运行代码,但我认为它抓住了这个想法。
【讨论】:
那只是一个错字,我更改了我的代码。我现在返回 movieTypes 问题仍然存在以上是关于在反应中获取多个网址时无法更新钩子变量的主要内容,如果未能解决你的问题,请参考以下文章
OnSubmit 函数不会更新 React 中的反应钩子状态变量