I am learning react and I struggle with the hooks. I am recreating a slightly simplified project from udemy. There are rows of items which you can add to cart. When pressing the "Add" button I receive the correct console.log for the item's ID but the issue lies with the input value where you can increase the number of items. Pressing any of the buttons only logs the last (bottom) input's value.
//////////////Menu.js//////////////////
import Card from "../UI/Card";
import MenuItem from "./MenuItem";
const MEALS = [
{
id: "m1",
name: "Sushi",
description: "Finest fish and veggies",
price: 22.99,
},
{
id: "m2",
name: "Schnitzel",
description: "A german specialty!",
price: 16.5,
},
{
id: "m3",
name: "Barbecue Burger",
description: "American, raw, meaty",
price: 12.99,
},
{
id: "m4",
name: "Green Bowl",
description: "Healthy...and green...",
price: 18.99,
},
];
const Menu = (props) => {
return (
<Card>
<ul>
<MenuItem MEALS={MEALS} />
</ul>
</Card>
);
};
export default Menu;
//////////////MenuItem.js//////////////////
import { useRef } from "react";
import Input from "../UI/Input";
const MenuItem = (props) => {
const amountInputRef = useRef();
const submitHandler = (e) => {
e.preventDefault();
console.log(e.target.id);
console.log(amountInputRef.current.value);
};
const mealItem = props.MEALS.map((e) => {
return (
<form id={e.id} key={Math.random()} onSubmit={submitHandler}>
<li>
{`${e.name} --- ${e.description} --- #${e.price}`}
<Input
ref={amountInputRef}
input={{
id: e.id,
type: "number",
min: "0",
max: "5",
}}
/>
<button className="small-btn">Add</button>
</li>
</form>
);
});
return mealItem;
};
export default MenuItem;
//////////////Input.js//////////////////
import React from "react";
const Input = React.forwardRef((props, ref) => {
return <input ref={ref} {...props.input} />;
});
export default Input;
I have tried to solve this on my own for hours. I asked ChatGPT plenty of questions and mostly received answers to use multiple refs. The chat provided some solutions but they did not work. I tried to get help from udemy but they are unwilling. The code looks very similar to the original exercise code but I have no clue why it is not working. I was advised to use multiple refs but this is not how it is done in the exercise.
I took a look at similar posts, useCallback is used in a similar example, but again this is not what is being used in the original app from udemy.
Here is a link to the files in git hub just in case. GitHub Any help is appreciated.
When a ref is used in React, it's automatically assigned to a given element only when that element mounts (when it is added to the DOM). In other words, since you pass all your input elements the same ref, and the last input of your list is the last to be added to the DOM, the ref will always equal the last input element.
You should be creating a ref per MenuItem
, where each MenuItem
represents one meal with one input. In other words, you should be rendering a list of MenuItems
(e.g. MEALS.map((meal) => <MenuItem ... />)
.
Alternatively, the new React Docs have a section on how to manage a list of refs: https://react.dev/learn/manipulating-the-dom-with-refs#how-to-manage-a-list-of-refs-using-a-ref-callback. While this is also a valid approach, it's likely more brittle for your use case.