Search code examples
arraysreactjsspliceuse-state

how to splice or push new elements in a specific index with usestate?


I'm trying to insert new elements in the array and update the state base on the array, but the problem after I update the state It doesn't get rendered in the component.

  • note: I'm not really sure how to use splice. ( I wanted the handleClick function to add new element under the clicked element but it seems I failed in that as well.)
  • note 2: I also tried setstate((pre) => { pre.splice(index + 1, 0, { id: 3, text: "xxx", autoFocus: true }); return pre; }); but didn't work as well.
import React, { useState } from "react";
import "./styles.css";

export default function App() {
  let elements = [
    { id: 0, text: "first", autoFocus: true },
    { id: 1, text: "second", autoFocus: true },
    { id: 2, text: "third", autoFocus: true }
  ];
  const [state, setstate] = useState(elements);

  function handChange(e) {
    if (e.keyCode == 13) {
      const x = state;
      const index = x.findIndex((item) => item.id == e.target.id);

      //i'm using autoFocus to move the focus  (I-beam pointer) to the nex field.
      //but i still get errors with it
      // e.map((item) => Object.assign(item, { autoFocus: false }));
      
      x.splice(index + 1, 0, { id: 3, text: "xxx", autoFocus: true });
      console.log(state); // you can see this update probarly
      setstate(x); // but when I update state sometimes it don't render othertimes it take a while before render.

    }
  }

  return (
    <div className="App">
      {state.map((e) => (
        // when I say it don't render I mean the e value don't get updated.
        <div
          focus={e.focus}
          contentEditable="true"
          id={e.id}
          onKeyUp={handChange}
        >
          {e.text}
        </div>
      ))}
    </div>
  );
}

on codesandbox


Solution

  • Instead of using

    x.splice(index + 1, 0, { id: 3, text: "xxx", autoFocus: true });
          setstate(x)
    

    I replace it with this code

    setstate((pre) => {
          
            return [
              ...pre.slice(0, index + 1),
              { id: 3, text: "xxx", autoFocus: true },
              ...pre.slice(index + 1, state.length)
            ];
          })
    

    that return the elements before the element on the index index + 1 + the new element + the elements after the element on the index index + 1

    • for example, if you have 3 elements and you hit enter on the 2d element then the index is of it is 1 and you will a create a new element in the index 1+1 and after it, you will return the third element which is in the area between 1+1, 3 in which 3 is the length of the array.

    alternative explanation:

    • ...pre.slice(0, index + 1), this return all elements before the element that you hit enter in it + the element that you hit enter in it.
    • { id: 3, text: "xxx", autoFocus: true }, this will create new elements after the previous elements
    • ...pre.slice(index + 1, state.length) this will return the elements after the element where you hited enter (in case of there is no it will return nothing)