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

React中基于前置获取用户数据获取对应观影记录的顺序错乱问题求助

Hey there, let's figure out why your movies array is getting out of order and how to fix it!

The core issue here is that asynchronous requests don't guarantee order—when you loop through your users and call fetchMovies for each, those API calls run in parallel. The first user's movie data might come back last, and since you're just appending each result to the movies array as it arrives, the order gets scrambled. That's why your MovieInfo components end up with mismatched user-movie pairs.

Let's go through two solid solutions, starting with the cleanest approach:


Instead of keeping separate users and movies arrays, we'll attach each user's movie data directly to their object. This eliminates the need to rely on array indexing to match users and movies entirely.

Here's how to adjust your code:

export default class Admin extends Component {
  constructor(props) {
    super(props);
    this.state = {
      users: [], // Now each user will have a `movies` property
    };
  }

  componentDidMount() {
    fetch('https://a-url/users/')
      .then((res) => res.json())
      .then((data) => {
        // Create a promise for each user's movie request
        const userMoviePromises = data.users.map(user => 
          fetch(`https://a-url/${user.name}/movies/`)
            .then(res => res.json())
            .then(movieData => ({
              ...user, // Keep all existing user data
              movies: movieData.movies // Add the user's movies
            }))
        );

        // Wait for ALL movie requests to finish before updating state
        Promise.all(userMoviePromises)
          .then(usersWithMovies => {
            this.setState({ users: usersWithMovies });
          });
      });
  }

  render() {
    const { users } = this.state;
    return (
      <div className='wum__admin section__padding'>
        {users.length > 0 ? (
          users.map(user => (
            <MovieInfo 
              key={user.id} 
              movies={user.movies} 
              id={user.id} 
              user={user.name} 
            />
          ))
        ) : (
          <div>Loading user data...</div>
        )}
      </div>
    );
  }
}

Why this works:

  • Promise.all ensures we only update the state once all movie requests are complete.
  • Each user object now contains its own movie data, so there's no chance of mismatched order.
  • The render logic becomes simpler—we just loop through users and pass their built-in movies property to MovieInfo.

Solution 2: Fix Array Order with Index Tracking

If you prefer to keep separate users and movies arrays, we can track the index of each user when fetching their movies, then update the exact position in the movies array instead of appending to the end.

Here's the adjusted code:

export default class Admin extends Component {
  constructor(props) {
    super(props);
    this.state = {
      users: [],
      movies: [],
    };
  }

  componentDidMount() {
    fetch('https://a-url/users/')
      .then((res) => res.json())
      .then((data) => {
        this.setState({ users: data.users });
        // Pass the user's index to fetchMovies
        data.users.forEach((user, index) => this.fetchMovies(user.name, index));
      });
  }

  fetchMovies = (user, index) => {
    fetch(`https://a-url/${user}/movies/`)
      .then((res) => res.json())
      .then((data) => {
        this.setState(prevState => {
          const newMovies = [...prevState.movies];
          newMovies[index] = data.movies; // Update the specific index for this user
          return { movies: newMovies };
        });
      });
  };

  render() {
    const { users, movies } = this.state;
    // Make sure all movies are loaded (no undefined entries)
    const isAllDataLoaded = users.length === movies.length && movies.every(movieList => movieList);

    return (
      <div className='wum__admin section__padding'>
        {isAllDataLoaded ? (
          users.map((user, i) => (
            <MovieInfo 
              key={user.id} 
              movies={movies[i]} 
              id={user.id} 
              user={user.name} 
            />
          ))
        ) : (
          <div>Loading...</div>
        )}
      </div>
    );
  }
}

Why this works:

  • We pass the user's index from the original users array to fetchMovies, so we know exactly where to place their movie data in the movies array.
  • Using prevState in setState ensures we're always working with the latest state when updating the array.
  • The isAllDataLoaded check ensures we only render once every user's movie data has been placed in the correct position.

What Was Wrong With Your Original Code?

  1. Unordered Async Requests: Your map call to fetchMovies runs all requests in parallel—there's no guarantee they'll resolve in the same order as your users array.
  2. Blindly Appending to Movies: By using [...this.state.movies, ...[data.movies]], you're adding each movie result to the end of the array, regardless of which user it belongs to.
  3. Fragile Index Matching: Using movies[user.id - 1] assumes user IDs are sequential and start at 1—this breaks if IDs are non-sequential or if the movies array order is wrong.

Either solution above will fix your matching issue, but Solution 1 is more maintainable long-term since it keeps related data together.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 16:27:35