1

Actually, I am stuck at a point, Please have a look the code once. I want to push the user input into my array. Can anyone explain why it's throwing error.

import React, { useState } from 'react';

function Cart() {
  const [item, setItem] = useState({ cart: ['Corn', 'Potato'] });

  const saveInput = (e) => {
    setItem({ input: e.target.value });
  };
  const addNewItem = () => {
    const { cart, input } = item;
    cart.push(input);
    return setItem({ cart: cart });
  };
  return (
    <div>
      <input type="text" onChange={saveInput} />
      <button onClick={addNewItem}>Add Item</button>
      <ol>
        {item.cart.map((subItems, sIndex) => {
          return <li key={sIndex}> {subItems}</li>;
        })}
      </ol>
    </div>
  );
}

export default Cart;
1
  • 2
    Use separate state for separate concerns. In your case you should have a state for the text input and one for items in your cart Commented Aug 25, 2021 at 8:17

3 Answers 3

2

Just like Dominik said, it would be much more efficient to have separate of your state.

If you want to make your existing code works:

Change

setItem({ input: e.target.value });

TO:

setItem({ ...item, input: e.target.value });

You forgot to spread your previous state before changing new ones.

Sign up to request clarification or add additional context in comments.

Comments

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

function Cart() {
  const [item, setItem] = useState({ cart: ["Corn", "Potato"] });
  // have a new state to hold the input value
  const [inputValue, setInputValue] = useState("");

  const saveInput = (e) => {
    setInputValue(e.target.value);
  };

  const addNewItem = () => {
    // spread the exisiting cardlist and append the newly added input value
    setItem((existingCartList) => ({
      cart: [...existingCartList.cart, inputValue]
    }));
    // clear the input once it is added to card list
    // so we can prevent the user from manually clearing it
    setInputValue("");
  };

  return (
    <div>
      
      {/* need to pass the inputValue state to the value attribute 
         which makes the input a controlled component */}

      <input type="text" value={inputValue} onChange={saveInput} />
      <button onClick={addNewItem}>Add Item</button>
      <ol>
        {item.cart.map((subItems, sIndex) => {
          return <li key={sIndex}> {subItems}</li>;
        })}
      </ol>
    </div>
  );
}

export default Cart;

Working Sandbox

Reference

Controlled Components

Comments

1

You can use separate states. One for handle input and another for handle list:

import React, { useState } from "react";

function Cart() {
  const [item, setItem] = useState(["Corn", "Potato"]);
  const [input, setInput] = useState(""); 

  const saveInput = (e) => {
    setInput(e.target.value);
  };
  const addNewItem = () => {
    const copyCart = [...item];
    copyCart.push(input);
    setItem(copyCart);
    setInput("");
  };
  return (
    <div>
      <input value={input} type="text" onChange={saveInput} />
      <button onClick={addNewItem}>Add Item</button>
      <ol>
        {item.map((subItems, sIndex) => {
          return <li key={sIndex}> {subItems}</li>;
        })}
      </ol>
    </div>
  );
}

export default function App() {
  return <Cart />;
}

Here's the full example:

Edit cool-wood-d6fik

Comments

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.