Не удается удалить определенные элементы из массива по номеру индекса из динамического элемента div в react?

#javascript #arrays #reactjs #use-state

Вопрос:

Я не могу удалить определенные элементы массива по номеру индекса из любого динамического div

 const { useState } = React;

function Check(){
  var [Children, setChildren] = useState([])
    
  function RemArr(docs){
    const temp = [...Children]
    temp.splice(docs["i"], 1);
    setChildren(temp)
  } 
    
  function Product(docs) {
    var document = (<React.Fragment>
      <button onClick={()=>RemArr(docs)}>
        List {docs["i"]}
      </button>
      <p></p>
      <input/>
      <p></p>
    </React.Fragment>);
    setChildren([...Children, document])
  }

  return (<React.Fragment>
    <div>Check</div>
    {Children}
    <button
     onClick={()=>{Product({fix:false, i:Children.length})}}
    >Add List </button>
  </React.Fragment>)
}

ReactDOM.render(<Check />, document.body); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script> 

Когда я хочу удалить какой-либо конкретный div, то не только этот div удаляют из массива, но и удаляют следующий div из массива.

Напр..

 array = [0,1,2,3,4,5,6,7,8,9]
 

Однако, если я хочу удалить только 6 из массива, вместо этого он удаляет все значения из 6 to 9 , и поэтому у меня остается только:

 array = [0,1,2,3,4,5]
 

Я думаю, что проблема возникает из-за этой функции:

 function RemArr(docs){
  const temp = [...Children]
  temp.splice(docs["i"], 1);
  setChildren(temp)
}
 

Ответ №1:

Ваша RemArr функция имеет закрытие Children , что означает , что нажатие на кнопку удалить вызовет потенциально старое объявление remArr , в котором remArr Children массив будет ссылаться на состояние дочернего массива с момента первоначального добавления обработчика события щелчка, а не на текущее состояние Children .

Чтобы преодолеть это, вы можете разбить его Product на компоненты, а не превращать в функцию , и ввести Children в него состояние, основанное на некотором состоянии Choice , которое вы можете использовать для создания элементов вашего продукта:

 const {useState} = React;

function Product({docs, onClick}){
  return <React.Fragment>
    <button onClick={onClick}>
      List {docs.i}
    </button>
    <p></p>
    <input/>
    <p></p>
  </React.Fragment>;
}

function Check() {
  const [products, setProducts] = useState([]);
  function remArr(index){
    const temp = [...products];
    temp.splice(index, 1);
    setProducts(temp);
  }
  
  function addProduct() {
    const prevNum = products[products.length-1];
    setProducts([...products, {
      fix: false, 
      i: prevNum === undefined ? 0 : prevNum.i   1
    }]);
  }

  return (<React.Fragment>
    <div>Check</div>
    {products.map(
      (doc, i) => <Product key={doc.i} docs={doc} onClick={() => remArr(i)}/>
    )}
    <button
     onClick={addProduct}
    >Add List</button>
  </React.Fragment>);
}

ReactDOM.render(<Check />, document.body); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script> 

Описанный выше .map() метод, который создает новые <Product /> компоненты, «обновляет»/переопределяет onClick функцию всех компонентов продукта, указывая на «последнюю» объявленную remArr функцию, которая имеет доступ к правильному/актуальному products массиву. Это не похоже на ваш пример, где старые объекты JSX внутри Children массива все еще имеют onClick атрибуты, которые ссылаются на старые объявления remArr функции (которые имеют доступ к старому Children состоянию массива).

Комментарии:

1. Я все еще не понимаю этого. В оперативном коде ремАрр имеет доступ к старым детям. Но разве не должно быть так и здесь, у remArr должен быть доступ к массиву старых продуктов?

2. @TusharShahi .map() , который создает новые <Product /> компоненты, «обновляет» onClick функцию всех компонентов, чтобы указать на «последнюю» объявленную remArr функцию, которая имеет доступ к правильному/обновленному products массиву. В то время как в коде OPs старые объекты JSX внутри дочернего массива все еще имеют onClick атрибуты, которые ссылаются на старые объявления remArr функции (которые имеют доступ к старому Children состоянию массива).

3. Эй, Ник Парсонс, Ваш код работает, но не полностью, потому что, если я удалю список 4 или любой другой, то он удалит номер 4, но мой ввод не удален из поля с номером 4.При нажатии для удаления всегда удаляется последний ввод. amp; Также мне нужно инициализировать функцию продукта внутри основной функции (Проверка), потому что мне нужно использовать useState, которое определено в функции проверки. Итак, как использовать функцию продукта внутри функции проверки? Пожалуйста. amp; Я использую следующий js

4. @MunnyReol привет, я обновил key опору, чтобы устранить проблему с вводом. С точки зрения инициализации продукта внутри проверки, это никогда не должно быть сделано. Вы можете поддерживать свое состояние под контролем, а затем передавать методы (такие как setProducs) в компонент продукта с помощью реквизитов, которые позволят вам обновить состояние вашего компонента проверки внутри продукта

5. @MunnyReol вы можете изменить i , чтобы он основывался на номере предыдущего элемента списка плюс 1. Я обновил фрагмент.