You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React多接口并行请求时console.log先输出undefined后返回目标响应的问题咨询

Why does movieDetails[0] log undefined initially when using Promise.all in React?

Problem Description

I'm working on a React component where I use Promise.all to fetch multiple movie-related APIs in parallel, storing the returned data in the movieDetails state. However, when I run console.log(movieDetails[0]), it outputs undefined on the first render, only showing the expected data after the API requests complete. Here's my component code:

import React, { useEffect, useState } from "react";
import { endpoint, apiKey } from "../api";
import Container from "../components/layouts/Container";

export default function Movie({ route }) {
  const { movieId } = route.params;
  const [movieDetails, setMovieDetails] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  const urls = [
    `${endpoint}/movie/${movieId}?api_key=${apiKey}`,
    `${endpoint}/movie/${movieId}/credits?api_key=${apiKey}`,
    `${endpoint}/movie/${movieId}/images?api_key=${apiKey}`,
    `${endpoint}/movie/${movieId}/reviews?api_key=${apiKey}`,
    `${endpoint}/movie/${movieId}/similar?api_key=${apiKey}`,
  ];

  useEffect(() => {
    const fetchData = () => {
      setIsLoading(true);
      Promise.all(
        urls.map((url) => {
          return fetch(url);
        })
      )
        .then((response) => {
          return Promise.all(response.map((res) => res.json()));
        })
        .then((data) => {
          setMovieDetails(data);
          setIsLoading(false);
        })
        .catch((err) => {
          console.log(err);
        });
    };
    fetchData();
  }, []);

  console.log(movieDetails[0]);
}

Root Cause

This happens because React state updates are asynchronous, and here's the breakdown of the component's lifecycle:

  1. On the initial mount, movieDetails is set to its default value: an empty array []. When the component renders the first time, movieDetails[0] is undefined, so that's what gets logged.
  2. The useEffect hook runs after the first render, kicking off the asynchronous API requests. This process doesn't block the component from rendering.
  3. Once all requests complete and setMovieDetails(data) is called, React schedules a re-render of the component. On this re-render, movieDetails holds the API response data, so console.log(movieDetails[0]) outputs the expected result.

In short, the first log runs before your API requests finish, so the state still has its initial empty value.


Solutions

1. Guard Against Empty State with Conditionals

Before accessing movieDetails[0], check if the state has data to avoid undefined:

// Only log when data exists
if (movieDetails.length > 0) {
  console.log(movieDetails[0]);
}

You can also extend this to conditionally render content in your component, which improves user experience by handling loading and empty states:

if (isLoading) {
  return <div>Loading movie details...</div>;
}

if (movieDetails.length === 0) {
  return <div>No movie data available</div>;
}

// Render your movie content once data is ready
return (
  <Container>
    <h1>{movieDetails[0].title}</h1>
    {/* Add other movie details here */}
  </Container>
);

2. Use Optional Chaining for Safe Property Access

If you want to avoid errors when accessing properties on movieDetails[0], use the ES6 optional chain operator ?. — it will return undefined instead of throwing an error if the parent value doesn't exist:

// Safely access a property without breaking the app
console.log(movieDetails[0]?.title);

3. Work with the API Response Directly (Instead of Waiting for State)

When your Promise.all resolves, you can work with the data variable directly instead of relying on the updated state (since state updates are async). This is useful if you need to process the data immediately after fetching:

.then((data) => {
  setMovieDetails(data);
  setIsLoading(false);
  // Log the data directly here — no wait for state update needed
  console.log(data[0]);
})

4. Fix the useEffect Dependency Array

Right now, your useEffect only runs once on mount, but if movieId changes (e.g., when navigating to a different movie), it won't re-fetch data. Add movieId to the dependency array to ensure the component fetches fresh data whenever the movie ID changes:

useEffect(() => {
  const fetchData = () => {
    // ... existing fetch logic
  };
  fetchData();
}, [movieId]); // Add movieId as a dependency

内容的提问来源于stack exchange,提问作者idan cohen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 21:14:08