Search code examples
reactjsuse-contextuse-reducer

Can't delete an item using useContext and useReducer


Please help guys. So I've started to learn about useReducer and useContext and I'm stuck at deleting an object. I've tried to log the result in the console and it prints the expected array that I want. However, when I return the array from the reducer, and whenever I delete an object, it clears the array and the button is left. So I've got this 2 js files below.

useContext & useReducer

import { createContext, useReducer } from "react";

const initialState = {
  items: [],
};

const reducer = (state, action) => {
  switch (action.type) {
    case "ADD_ITEM":
      return { ...state, items: [action.payload, ...state.items] };
    case "DEL_ITEM":
      return {
        ...state,
        items: [state.items.filter((item) => item.id !== action.payload)],
      };
    default:
      return state;
  }
};

export const ItemContext = createContext(initialState);

export const ItemProvider = (props) => {
  const [state, dispatch] = useReducer(reducer, initialState);

  const addItem = (item) => {
    dispatch({ type: "ADD_ITEM", payload: item });
  };

  const delItem = (id) => {
    dispatch({ type: "DEL_ITEM", payload: id });
  };

  return (
    <ItemContext.Provider value={{ items: state.items, addItem, delItem }}>
      {props.children}
    </ItemContext.Provider>
  );
};
import React, { useContext, useState } from "react";
import { ItemContext } from "../Context/ItemContext";

const Test2 = () => {
  const { items } = useContext(ItemContext);

  const { addItem } = useContext(ItemContext);

  const { delItem } = useContext(ItemContext);

  const [name, setName] = useState("");

  const [price, setPrice] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();

    const newItem = {
      id: items.length + 1,
      name: name,
      price: price,
    };

    addItem(newItem);

    setName("");
    setPrice("");

    console.log(newItem);
  };

  const handleDelete = (id) => {
    delItem(id);
  };

  return (
    <div>
      <div>
        <form>
          <label>Product Name:</label>
          <input
            type="text"
            value={name}
            onChange={(e) => setName(e.target.value)}
          />
          <label>Product Price:</label>
          <input
            type="text"
            value={price}
            onChange={(e) => setPrice(e.target.value)}
          />
          <button onClick={handleSubmit}>Submit</button>
        </form>
      </div>
      <div>
        {items.map((item) => (
          <div key={item.id}>
            <li>
              <p>{item.name}</p>
              <p>{item.price}</p>
            </li>
            <button onClick={() => handleDelete(item.id)}>X</button>
          </div>
        ))}
      </div>
    </div>
  );
};

export default Test2;

Solution

  • The Array.filter() already returns a new array, so when you're putting it into [], you are creating an array which contains an array as your items as the first element.

    case "DEL_ITEM":
          return {
            ...state,
            items: state.items.filter((item) => item.id !== action.payload),
          };
    

    is therefore correct.