在反应中获取多个网址时无法更新钩子变量
unable to update hooks variable when fetching multiple urls in react
我正在尝试使用自定义反应挂钩存储来自 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>
);
}
我什么都没有,没有电影显示。非常感谢您对此的帮助。
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);
}
试试这个
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();
},[]);
您没有从 useFetch
收到任何值的原因(假设 return 有值)是因为您 return 结构 { 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 alt="movie" src={path} />
<h4 className="movie-overview">{movie.overview}</h4>
<p className="movie-title">{movie.title}</p>
</div>
})
}
</div>
);
}
请注意,提取请求已重组以传播承诺,而不是重复等待承诺。当所有的获取承诺都解决时,数组被展平并设置状态变量。如果发生错误,则会报告。我没有 运行 代码,但我认为它抓住了这个想法。
我正在尝试使用自定义反应挂钩存储来自 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>
);
}
我什么都没有,没有电影显示。非常感谢您对此的帮助。
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);
}
试试这个
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();
},[]);
您没有从 useFetch
收到任何值的原因(假设 return 有值)是因为您 return 结构 { 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 alt="movie" src={path} />
<h4 className="movie-overview">{movie.overview}</h4>
<p className="movie-title">{movie.title}</p>
</div>
})
}
</div>
);
}
请注意,提取请求已重组以传播承诺,而不是重复等待承诺。当所有的获取承诺都解决时,数组被展平并设置状态变量。如果发生错误,则会报告。我没有 运行 代码,但我认为它抓住了这个想法。