简体   繁体   中英

array.map() does not work as expected to render <li> component in React

I want to render multiple <li> components using map() function. Nothing is rendered on the screen. I don't get any error message either, so I have no clue.

        reviewCard = reviews.map((review, index) => {
            const url = `http://localhost:3001/users/${review.user_id}`;
            axios
                .get(url)
                .then(response => {
                    return (
                        <li key={index}>
                            <ReviewCard 
                                review={review} 
                                user={response.data}
                            />
                        </li>
                    );
                })
                .catch(error => {
                    console.log(error);
                });
            }
        );

The following code works though.

        reviewCard = reviews.map((review, index) => (
            <li key={index}>
                <ReviewCard review={review} />
            </li>
        ));

I would appreciate it if you have any suggestion.

Thanks:)

You can 1st use promise all to resolve all async code and then map the to create your ReviewCard

let promiseList = reviews.map((review, index) => {
  const url = `http://localhost:3001/users/${review.user_id}`;
  return axios.get(url);
});

let reviewCard;
Promise.all(promiseList).then((responses) => {
  reviewCard = responses.map((response,index) => {
    return (
      <li key={index}>
        <ReviewCard review={review[index]} user={response.data} />
      </li>
    );
  });
});

Explanation:

  1. Firstly we are creating an array of promises ie your get requests.
  2. Now we resolve all the promises requests using promise.all so that we can finally get an array of responses.
  3. Now we have all sync code so we easily can map the responses array to our ReviewCard.

JSX is not the best place to call some async functions. Axios then doesn't call rerender of your component. You have to use useEffect to call axios method and useState for rerender you component and store the results.

Just see the next code:

import React, { useEffect, useState, useCallback } from 'react';

const Cards = ({ reviews }) => {
  const [isLoading, setIsLoading] = useState(true);
  const [users, setUsers] = useState([]); // use state rerender component on each call setUsers;

  const fetchUsers = useCallback(() => {
    try {
      // collect user requests to array
      const listOfRequests = reviews.map((item) => axios.get(`http://localhost:3001/users/${item.user_id}`));
      const responses = await Promise.all(listOfRequests);
      const users = responses.map((item) => item.data);
      setUsers(users);
      setIsLoading(false);
    } catch(error) {
      console.error(error);
      setIsLoading(false);
    }
  }, []);


  useEffect(() => {
    fetchUsers();
  }, []);

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

  if (users.length === 0) {
    return <div>something happens</div>
  }

  return (
    <ul>
      {users.map((user) => <li key={user.id}><Review user={user} /></li>)}
    </ul>
  )
}


The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM