我是React和Hooks的新手。我试图从某个API中获取一个对象,对其进行转换(基于另一个API的结果),并更新useEffect挂钩内的状态。但是,渲染DOM时不会反映对象转换。这是我的代码。
useEffect(() => {
let modified_movies = []
axios.get(LOCAL_MOVIE_API)
.then(res => {
const movies = res.data.content;
movies.map(async movie => {
const response = await axios.get(_API,
{
params: {
query: movieTitle,
year: movie.movieYear
}
});
const poster = response.poster; //add property to object
const modified_movie = { ...movie, poster_url: poster };
modified_movies.push(modified_movie)
})
setMovies(modified_movies) //
})
}, [])
我也没有就地修改对象,因此不能复制对象,但是react仍然不会用修改后的对象更新状态,并且新属性不会反映在视图中。是我遗漏了明显的东西还是有更好的方法实现这一目标?
答案 0 :(得分:2)
与反应无关。
您的movies.map(async movie => {...
调用正在创建Promise
,将在您的setMovies
调用之后执行,因此modified_movies
数组将为空。因此,您需要等待map
函数完成,然后设置状态。
解决问题的一种方法:
useEffect(() => {
let modified_movies = []
axios.get(LOCAL_MOVIE_API)
.then(res => {
const movies = res.data.content;
const moviePromises = movies.map(async movie => await axios.get(_API,
{
params: {
query: movieTitle,
year: movie.movieYear
}
})
) // map all the calls into one array
Promise.all(moviePromises).then((allResponses) => {
// allResponses will be an array of values, which you can map to your needs
setMovies(allResponses) //
})
})
}, [])
以下是一些有用的文档:
答案 1 :(得分:1)
这与React或useEffect无关。
您只是对Promise有问题。
考虑以下示例:
// ----------- YOUR WAY --------------
const getRandomValue = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(Math.random());
}, 10);
});
};
const movies = [1, 2, 3];
const modified_movies = [];
movies.map(async(movie) => {
modified_movies.push(await getRandomValue());
});
console.log("modified movies with map", modified_movies);
// ---------- One of correct ways -----------------
const Movies = [1, 2, 3];
const modifiedMovies = [];
const getModifiedMovies = async() => {
for (let movie in movies) {
modifiedMovies.push(await getRandomValue());
}
};
getModifiedMovies().then(() => {
console.log("modified movies with for let", modifiedMovies);
});
第一种方法模拟了您的方式,总是返回一个空数组。
第二种方法等待所有诺言得到解决,从而返回正确的诺言。
回到您的问题,我认为代码应类似于以下内容:
axios.get(LOCAL_MOVIE_API)
.then(async(res) => {
const movies = res.data.content;
for (const movie of movies) {
const response = await axios.get(_API, {
params: {
query: movieTitle,
year: movie.movieYear
}
});
const poster = response.poster; //add property to object
const modified_movie = { ...movie,
poster_url: poster
};
modified_movies.push(modified_movie);
}
setMovies(modified_movies);
});
答案 2 :(得分:-2)
您需要提供应在哪个状态更改上触发useEffect,如下所示:
useEffect(() => {
// your logic here
})
}, [theStateWhichChanged])
答案 3 :(得分:-2)
您的依赖项数组为空,这意味着useEffect内部的代码在组件安装时执行,并且仅在此时间执行。 对我来说,代码看起来过于复杂且缺少部分(movieTitle,movie.movieYear来自何处?)。建议您将请求拆分到useEffect内的函数中,以使自己更加清楚。
如果状态取决于效果(例如另一个状态),则需要将i添加到依赖项数组中:
React.useEffect(() => {
// your code here
}, [movies])