1

Okay! So questions similar to this have already been asked but the problem is that they don't solve my exact problem so please read the full question and consider looking at the code snippet pasted below before marking it as duplicate. So I have an array of objects menuItems which holds the props for another component MenuItem, and I'm trying to render that component MenuItem multiple times by iterating through that array "menuItems" and assigning unique props to it and then pushing it to another array called items and when this is done I'm placing this items array inside the return but somehow react is not rendering that array at all.

function Menu() {

    let items = [];

    const menuItems = [
        {
            imageName:'food-header-2.jpg',
            itemTitle:'Full breakfast for morning',
            itemPunchLine:'Some punchline',
            quantity:0,
        },
        {
            imageName:'pizza.jpg',
            itemTitle:'Cheeze pizza',
            itemPunchLine:'Some punchline',
            quantity:0,
        },
        {
            imageName:'burger.jpg',
            itemTitle:'Jumbo Burger',
            itemPunchLine:"Some punchline",
            quantity:0,
        },
        {
            imageName:'sandwich.jpg',
            itemTitle:'Veg SandWich',
            itemPunchLine:'Some punchline',
            quantity:0,
        },
        {
            imageName:'chocolate-shake.jpg',
            itemTitle:'Chocolate Shake',
            itemPunchLine:'Some punchline',
            quantity:0,
        },
    ]

    const useEffect(() => {

        menuItems.forEach((menuItem,index) => {
            items.push(
            <MenuItem key={index} title={menuItem.itemTitle} punchLine={menuItem.itemPunchLine} 
            quantity={menuItem.quantity} imageName={menuItem.imageName}
            />);
        }));

        
    };
    return(
        <div className="container">
            <div className="menu-holder">
                <div className="menu">
                    {items}                 
                </div>
            </div>            
        </div>
    )
}

2 Answers 2

3

items is a plain array. It's not a stateful value (i.e using useState hook). React will not re-render when this value changes.

Instead you should render the menuItems directly using map in your return statement:

 return(
    <div className="container">
        <div className="menu-holder">
            <div className="menu">
                {menuItems.map((menuItem,index) => 
                  <MenuItem
                    key={index} 
                    title={menuItem.itemTitle} 
                    punchLine={menuItem.itemPunchLine} 
                    quantity={menuItem.quantity}
                    imageName={menuItem.imageName}
                  />)}
            </div>
        </div>
    </div>
)

...

If you wanted to keep the items array for some reason, to follow this approach you need to convert it to react state.

You could achieve it like so:

import React, { useEffect, useState } from "react";

const menuItems = [
  {
      imageName:'food-header-2.jpg',
      itemTitle:'Full breakfast for morning',
      itemPunchLine:'Some punchline',
      quantity:0,
  }
]

function Menu() {
  const [items, setItems] = useState([]);

  useEffect(() => {
    setItems(menuItems)
  }, [])

  return(
      <div className="container">
          <div className="menu-holder">
              <div className="menu">
                {items.map((menuItem,index) => 
                  <MenuItem
                    key={index} 
                    title={menuItem.itemTitle} 
                    punchLine={menuItem.itemPunchLine} 
                    quantity={menuItem.quantity}
                    imageName={menuItem.imageName}
                  />)}
              </div>
          </div>
      </div>
  )
}

However if you know the menuItems at render time, it would be more efficient to set the initial state to this straight away (rather than setting it after render in the useEffect hook:

  const [items, setItems] = useState(menuItems);
Sign up to request clarification or add additional context in comments.

2 Comments

This worked perfectly fine but then I tried to use the same array.map inside the useEffect hook and then try to render the array it stops working and react throws an error Objects are not valid as React Child I want to ask why is it so? and how does map makes the array stateful?
I've extended the answer, to try and show the patterns you should use. map does not make a value stateful in React, it is simply a way to iterate over an array and return a new array.
2

For React to watch for state changes you can use useState hook to track the change in the state of the array.

const [items, setItems] = useState([])

1 Comment

Do you mean I should do setItems([...items, newItem]) inside the menuItems.forEach loop?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.