Search code examples
reactjscomponentsfetch

Fetch items before render component


I have code like this below and my question is what can I do to get the products fetched before the components are rendered? I mean in my Panel component I have a .map function which shows an error "Cannot read property 'map' of undefined" because products were not fetched quickly enough.

const Announcments = () => {
  const [announcements, setAnnouncement] = useState([]);

  useEffect(() => {
    const getProducts = async () => {
      const res = await fetch("http://localhost:8000/api/products", {
        method: "GET",
      });
      const data = await res.json();
      await setAnnouncement(data);
    };
    getProducts();
  }, []);

  return (
    <div className="announcments">
      <TopNav results={announcements.length} />
      <Panel announcements={announcements} />
      <div className="down-pages-list">
        <PagesList />
      </div>
    </div>
  );
};

.map function:

{announcements.results.map((announcement) => (
          <SingleAnnoun
            price={announcement.price}
            title={announcement.name}
            photo={getPhoto(announcement.images[0].file_name)}
          />
        ))}

Solution

  • Issue

    The issue here isn't that "products were not fetched quickly enough" but rather that your initial state doesn't match what you are attempting to render on the initial render. I.e. announcements is initially an empty array ([]) but you are attempting to map announcements.results which is obviously undefined.

    Solution

    Use valid initial state so there is something to initially render.

    const [announcements, setAnnouncement] = useState({ results: [] });
    

    Now announcements.results is defined and mappable.

    This also assumes, of course, that your setAnnouncement(data); state update is also correct. i.e. that your JSON data is an object with a results property that is an array.

    BTW, setAnnouncement is a synchronous function so there is nothing to await for.