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:
Solution 1: Tie Movie Data Directly to Users (Recommended)
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.allensures 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
moviesproperty toMovieInfo.
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
usersarray tofetchMovies, so we know exactly where to place their movie data in themoviesarray. - Using
prevStateinsetStateensures we're always working with the latest state when updating the array. - The
isAllDataLoadedcheck ensures we only render once every user's movie data has been placed in the correct position.
What Was Wrong With Your Original Code?
- Unordered Async Requests: Your
mapcall tofetchMoviesruns all requests in parallel—there's no guarantee they'll resolve in the same order as yourusersarray. - 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. - 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 themoviesarray 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

