event.stopPropagation, похоже, предотвращает обновление и рендеринг useState

У меня есть несколько строк в списке, которые представляют собой панели расширения Material-UI. Строки отображаются из массива rowData. Каждая строка может расширяться. У каждой строки также есть значок удаления, который при нажатии должен удалить строку.

Первая проблема заключается в том, что когда я нажимаю DeleteIcon, строка удаляется, но щелчок распространяется и открывает следующую панель.

<DeleteIcon
  id={key}
  onClick={event => {
     onDelete(event, key); //key is specific row id
  }}
  className={classes.icons}
/>

const onDelete = (event, key) => {
    let newCategories = categories;
    delete newCategories[key];
    setCategories(newCategories);
};

Сначала я попытался установить для панели значение false, чтобы закрыть ее:

const [expanded, setExpanded] = useState(false);
...
const onDelete = (event, key) => {
  setExpanded(false)
...

но это не работает, потому что, как я предполагаю, мой щелчок распространяется, а панель под удаленной строкой открывается из функции события щелчка, которая запускается после onDelete ().

Итак, затем я попытался использовать event.stopPropagation:

const onDelete = (event, key) => {
    event.stopPropagation();
    let newCategories = categories;
    delete newCategories[key];
    setCategories(newCategories);
  };

Но теперь строка не удаляется в представлении (это происходит в консоли). Я предполагаю, что event.stopPropagation не позволяет моему состоянию (setCategories) принудительно повторять рендеринг, как это обычно происходит с изменениями внутри хука useState. Однако, если я нажимаю значок удаления, то после того, как я нажимаю строку, чтобы развернуть панель, состояние обновляется, а строка удаляется. Итак, я удалил event.stopPropagation, и теперь у меня есть следующее:

const onDelete = (event, key) => {
    let newCategories = categories;
    delete newCategories[key];
    setCategories(newCategories);
    setTimeout(() => {
      setExpanded(false);
    }, 100);
};

Это работает и добавляет аккуратный небольшой эффект, когда следующая панель открывается очень быстро до того, как строка будет удалена, но я хотел бы лучше понять, что происходит с использованием event.stopPropagation и состояния обновления с помощью хуков useState.

РЕДАКТИРОВАТЬ:

Ссылка на codeandbox: https://codesandbox.io/embed/61j19k1q13

Я оставил event.stopPropagation () в функции onDelete () для тестирования. Щелкните значок удаления и смотрите, что ничего не происходит. Затем щелкните строку, чтобы развернуть панель и заметить, что она исчезает. Спасибо!


person John McNeill    schedule 13.05.2019    source источник
comment
Создайте CodeSandbox с изображением вашей проблемы. event.stopPropagation() не должен влиять на то, вызывает ли изменение состояния повторный рендеринг.   -  person Ryan Cogswell    schedule 14.05.2019
comment
Добавлена ​​ссылка на песочницу кода выше. Спасибо!   -  person John McNeill    schedule 14.05.2019


Ответы (1)


React избегает повторного рендеринга, потому что вы вызвали установщик состояния с тем же самым объектом. Вы должны создавать новый объект, а не изменять существующий объект, чтобы гарантировать, что установщик запускает повторный рендеринг.

Измените это:

const onDelete = (event, key) => {
    let newCategories = categories; // this line is the problem
    delete newCategories[key];
    setCategories(newCategories);
};

вместо этого быть:

const onDelete = (event, key) => {
    // create a new object rather than mutating existing object
    let newCategories = { ...categories }; 
    delete newCategories[key];
    setCategories(newCategories);
};
person Ryan Cogswell    schedule 13.05.2019