0

I'm trying to make a dynamic burger builder in ReactJS. As soon as the homepage opens, I get an error like this:

TypeError: Cannot read property 'name' of undefined
IngredientsMenuItem
/src/components/IngredientsMenu/IngredientsMenuItem.js:18
  15 | return (
  16 |     <ItemWrapper>
  17 |         <ItemContent>
> 18 |             <h3>{item.ingredient.name}</h3>
     | ^  19 |             <h4>{item.ingredient.price}</h4>
  20 |                 <Counter
  21 |                     value={item.qty}

I keep my burger in a context.

My ingredients file:

export const ingredients= [
    {
        name:"salad",
        price:0.5,
    },
    {
        name:"cheese",
        price:0.4,
    },
    {
        name:"meat",
        price:1.3,
    },
];

My home page:

const Home = () => {
    const {burger,updateBurger} = useContext(BurgerContext);

    return (
        <div>
            {!burger.length && updateBurger(buildBurger(ingredients))}
            <Burger/>
            <IngredientsMenu
                ingredients={ingredients}
            />
        </div>
    )
}

export default Home

My buildBurger function:

export const buildBurger = (ingredients) => {
    return [
        ingredients.map((ingredient) => (
            {
                qty:0,
                ingredient: ingredient
            }
        ))
    ]
} 

I did this to create a template for ingredients with values ​​0 in the initial state.

My IngredientsMenu:

const IngredientsMenu = ({ingredients}) => {
    const {burger, updateBurger} = useContext(BurgerContext);
    return (
        <>
        
        <Wrapper>
            {burger.map((item) => (
                <IngredientsMenuItem
                    item={item}
                />
            ))}
        </Wrapper>
        </>
    )
}

export default IngredientsMenu

My IngredientsMenuItem:

const IngredientsMenuItem = ({item) => {
    const {burger, updateBurger} = useContext(BurgerContext);
    const handleIncrement = (burgerItem) => {
        
    }
    const handleDecrement = (burgerItem) => {
        
    }
    
    return (
        <ItemWrapper>
            <ItemContent>
                <h3>{item.ingredient.name}</h3>
                <h4>{item.ingredient.price}</h4>
                    <Counter
                        value={item.qty}
                        onIncrement={() => handleIncrement(item)}
                        onDecrement={() => handleDecrement(item)}
                    />
            </ItemContent>
        </ItemWrapper>
    )
}

export default IngredientsMenuItem

I couldn't see where my fault was. Is there anyone who can help?

4
  • 1
    In my answer I'm assuming that you have your app wrapped with the context provider of BurgerContext... Are you? Commented Nov 4, 2020 at 22:12
  • You are missing a curly brace } after item here: const IngredientsMenuItem = ({item) => { Commented Nov 4, 2020 at 23:51
  • As a best practice, this sort of logic should not be inside of the return statement: {!burger.length && updateBurger(buildBurger(ingredients))} Commented Nov 4, 2020 at 23:55
  • 1
    @LindaPaiste The curly braces are not missing in the original code, I think there was an error copying it. You are right about the other issue, I'm a little new in this stuff :) I moved that part in useEffect, I guess now it's better. Thanks for your answer, I am really appreciate :) Commented Nov 5, 2020 at 19:08

1 Answer 1

1

On your component IngredientsMenuItem, the item prop is probably null or undefined.

Consider adding a console.log instruction inside your component to see what's exactly there.

If you want your code to "never break", you can check if the contents are there, and if they are not, revert to an empty object, like so:

const IngredientsMenuItem = ({item) => {
    const {burger, updateBurger} = useContext(BurgerContext);
    const handleIncrement = (burgerItem) => {
        
    }
    const handleDecrement = (burgerItem) => {
        
    }

    const ingredient = (item && item.ingredient) || {};
    // this can be replaced to a shorter version if you support the `?.` operator:
    // const ingredient = item?.ingredient || {};

    const qty = (item && item.qty) || 0;
    
    return (
        <ItemWrapper>
            <ItemContent>
                <h3>{ingredient.name}</h3>
                <h4>{ingredient.price}</h4>
                    <Counter
                        value={qty}
                        onIncrement={() => handleIncrement(item)}
                        onDecrement={() => handleDecrement(item)}
                    />
            </ItemContent>
        </ItemWrapper>
    )
}
Sign up to request clarification or add additional context in comments.

1 Comment

Yes, my code is wrapped with BurgerContext provider and I found the answer :) Yes, my item prop is undefined because I have returned an array in the buildBurder function, so it's an array inside the array. Therefore, when I say item.ingredient directly, it cannot find it. Thanks for your answer, I am really appreciate :)

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.