javascriptreactjsreact-hooksshopping-cartuse-reducer

after adding two list delete cycle is not property working in react useReducer?


I am creating a shopping cart lit application, in that program add functionality is fine but when I add one list then another enter code hereenter image description here

and then remove the one that is fine but when you want to delete two that is not able to deleted, also using the key={index} for identify each elements so what is the problem? enter image description here

import { useReducer, useRef } from "react";
export default function App() {
  const inputRef = useRef();
  const [items, dispatch] = useReducer((state, action) => {
    switch (action.type) {
      case "add":
        return [
          ...state,
          {
            id: state.length,
            name: action.name
          }
        ];
      case "remove":
        return state.filter((x) => x.id !== action.index);
      default:
        return state;
    }
  }, []);
  function handleSubmit(e) {
    e.preventDefault();
    if (inputRef.current.value !== "") {
      dispatch({
        type: "add",
        name: inputRef.current.value
      });
    }
    inputRef.current.value = "";
  }

  return (
    <div className="App">
      <form onSubmit={handleSubmit}>
        <input ref={inputRef} />
      </form>
      <ul>
        {items.map((item, index) => (
          <li key={index}>
            {item.name}
            <button onClick={() => dispatch({ type: "remove", index })}>
              X
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

Solution

  • The original id of an item is based on the current length of the array, so the id and the index of the item are identical. As soon as you delete an item from the start/middle of the items, the indexes of all items after no longer match the id. Instead use the id and not the index, whenever you wish to remove an item.

    In addition, don't depend on the length of the array, since deleting an item, and then adding another one would cause two items to have the same id. Use a uuid library or the native Crypto.randomUUID():

    const { useReducer, useRef } = React;
    
    const reducer = (state, action) => {
      switch (action.type) {
        case "add":
          return [
            ...state,
            {
              id: crypto.randomUUID(),
              name: action.name
            }
          ];
        case "remove":
          return state.filter(x => x.id !== action.id);
        default:
          return state;
      }
    }
    
    function App() {
      const inputRef = useRef();
      const [items, dispatch] = useReducer(reducer, []);
    
      function handleSubmit(e) {
        e.preventDefault();
        if (inputRef.current.value !== "") {
          dispatch({
            type: "add",
            name: inputRef.current.value
          });
        }
        inputRef.current.value = "";
      }
    
      return (
        <div className="App">
          <form onSubmit={handleSubmit}>
            <input ref={inputRef} />
          </form>
          <ul>
            {items.map(({ name, id }) => (
              <li key={id}>
                {name}
                <button onClick={() => dispatch({ type: "remove", id })}>
                  X
                </button>
              </li>
            ))}
          </ul>
        </div>
      );
    }
    
    ReactDOM
      .createRoot(root)
      .render(<App />);
    <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    
    <div id="root"></div>