state variable has wrong value in functional component

Viewed 555

Im trying to add and remove input box in a form. I will controll this box with useState hook. I dont have any problem with add in state variable but when I want to remove from state variable, state variable has wrong value.

import React, { useState } from 'react';
export default function Addable() {
  const [element, setElement] = useState([]);
  function add() {
    const list = [...element];
    const length = element.length;
    list.push(
      <React.Fragment>
        <input key={length} />
        <button onClick={()=>{_delete(length)}}>delete</button>
      </React.Fragment>,
    );
    setElement(list);
  }
  function _delete(index) {
    //****element has wrong value here****//
    const list = [...element];
    list.splice(index, 1);
    setElement(list);
  }
  return (
    <React.Fragment>
      <button onClick={add}>add Element</button>
      {element}
    </React.Fragment>
  );
}
1 Answers

The slice function won't change list array

const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];
animals.slice(2)
console.log(animals);

You might want to use splice instead, to prevent closure problem, pass a function to settlement to set the state on the current state

function _delete(index) {
    //****element has wrong value here****//
    console.log(element);
    setElement((currentEl) => {
      const list = [...currentEl];
      list.splice(index, 1);
      return list
    });
  }

NOTE: If you use an uncontrolled input component, you need to generate a unique id for input and set it as a key. because React will check key to know which element is to be removed. For example, you have element has length 5, then you remove element index 2 so now element has length 4 but index 2 still there, so React doesn't know you delete index 2 (cuz key 2 is still there) so it will shift 3 to 2, 4 to 3.. Check this for a better explanation and demo

You need to create a unique id, uuid as a choice

function add() {
    const list = [...element];
    const length = element.length;
    const uniqueId = uuid()
    list.push(
     {id: uniqueId
      comp: () => (<React.Fragment>
        <input key={uniqueId} />
        // index is length-1
        <button onClick={()=>{_delete(uniqueId)}}>delete</button>
      </React.Fragment>)
     }
    );
    setElement(list);
  }

function _delete(elementId) {
   // Because we set new state on current state
   // it's better to pass an function into setElement like this to prevent some problem with closure
   setElement(currently =>{
      return currently.filter(el => el.id !== elementId );
    });
}
return (
  <React.Fragment>
    <button onClick={add}>add Element</button>
    {element.map(el => el.comp())}
  </React.Fragment>
);

Edit hidden-currying-hmh4m

Related