Ненужное удаление элементов из dom без каких-либо действий с этими элементами - PullRequest
1 голос
/ 20 июня 2019
import React, { useState, useCallback } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

const CreateCriteria = () => {

  const [criteria, setCriteria] = useState({})

  const onClose = useCallback((key) => {
    delete criteria[key]
    setCriteria(criteria)
  }, [criteria])

  const onClick = useCallback(() =>{
    const key = Math.random()
    setCriteria({
      ...criteria,
      [key]: <div onClick={() => onClose(key)}>{
        key
      }</div>
    })
  }, [criteria, onClose])


  return (
    <div>
     {
       Object.keys(criteria).map((entity) => criteria[entity])
     }
    <button onClick={onClick}>
      add
    </button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<CreateCriteria />, rootElement);

Представьте, что у меня есть этот фрагмент кода.Когда я нажимаю кнопку add, я хочу получить новые элементы в DOM и в объекте критериев.Я делаю это, генерируя новый номинал (key/value) в объекте критериев, а затем анализирую эти новые данные в DOM.Я делаю это потому, что хочу также иметь возможность удалить этот объект из DOM, нажав на этот объект.Когда я нажимаю на элементы от последнего к первому (снизу вверх), то это работает нормально, но, например, если у меня есть 3 элемента 1,2,3, и я нажимаю на 2, то это также удаляет 3, и я могуне понимаю, почему это происходит.Вы можете использовать CodeSandbox для проверки:

https://codesandbox.io

Ответы [ 2 ]

1 голос
/ 21 июня 2019

Вы допустили две ошибки

  1. Вы вручную создали замыкание при добавлении новых ключей в creteria объект.Этот код

    [key]: <div onClick={() => onClose(key)}>{
        key
    }</div>
    

    не только добавляет элемент <div> к объекту creteria, но и создает замыкание с помощью функции onClose.onClose в свою очередь, create включает в замыкание creteria объект, как во время добавления нового ключа в creteria объект.Поэтому, когда onClose вызывается, он имеет только ключи, которые были там, когда добавлялся новый ключ.Итак, вы видите странное поведение.

    Для решения проблемы я предлагаю хранить только ключи в creteria объекте и инкапсулировать их в <div> во время рендеринга.

  2. Другая проблемауказал в комментариях.Вы должны создать новый creteria объект в onClose.В противном случае React не обновит creterai, поскольку сравнивает только новое и старое состояние, используя Object.is

    . Чтобы решить эту проблему, используйте оператор destruct для создания новой копии creteria объекта, подобного этому

    const onClose = useCallback((key) => {
        let newCreteria = { ...criteria };
        delete newCreteria[key];
        setCriteria(newCreteria);
    }, [criteria])
    

Также useCallback бесполезен.Но код работает с ними на месте.

Рабочий пример здесь

0 голосов
/ 21 июня 2019
const CreateCriteria = () => {
  const [criteria, setCriteria] = useState({});

  const deleteCriteria = useCallback(
    key => {
      const newCreteria = { ...criteria };
      delete newCreteria[key];
      setCriteria(newCreteria);
    },
    [criteria]
  );

  const onClick = useCallback(() => {
    const key = Math.random();
    setCriteria({
      ...criteria,
      [key]: null
    });
  }, [criteria]);

  const CriteriaList = useMemo(() => (
    Object.keys(criteria).map(entity => (
      <div key={entity} onClick={() => deleteCriteria(entity)}>
        {entity}
      </div>
    ))
  ), [criteria, deleteCriteria])

  return (
    <div>
      {CriteriaList}
      <button
      onClick={onClick}
      >
        add
      </button>
    </div>
  );
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...