event.stopPropagation 似乎阻止了 useState 更新和渲染
event.stopPropagation seems to prevent useState update and render
我在列表中有多行 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 挂钩。
编辑:
Link 到 codesandbox: https://codesandbox.io/embed/61j19k1q13
我在 onDelete() 函数中留下了 event.stopPropagation() 来测试。单击删除图标,看什么也没有发生。然后单击该行以展开面板并注意它消失了。谢谢!
React 正在避免 re-render,因为您使用完全相同的对象调用状态 setter。您应该创建一个新对象而不是改变现有对象,以保证 setter 触发 re-render.
改变这个:
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);
};
我在列表中有多行 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 挂钩。
编辑:
Link 到 codesandbox: https://codesandbox.io/embed/61j19k1q13
我在 onDelete() 函数中留下了 event.stopPropagation() 来测试。单击删除图标,看什么也没有发生。然后单击该行以展开面板并注意它消失了。谢谢!
React 正在避免 re-render,因为您使用完全相同的对象调用状态 setter。您应该创建一个新对象而不是改变现有对象,以保证 setter 触发 re-render.
改变这个:
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);
};