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
和条件对象中获取新元素。我通过在criteria对象中生成新的par(key/value
),然后在DOM中解析此新数据来做到这一点。我这样做是因为我还希望有机会通过单击此对象从dom中删除该对象。当我单击从最后到第一(从下到上)的元素时,它可以正常工作,但是例如,如果我有3、1、2、3个元素,然后单击2,那么它也会删除3,并且我可以找不到原因。您可以使用CodeSandbox
进行检查:
答案 0 :(得分:1)
您犯了两个错误
在creteria
对象中添加新键时,您在空间上创建了closure。这段代码
[key]: <div onClick={() => onClose(key)}>{
key
}</div>
不仅将<div>
元素添加到creteria
对象,而且使用函数onClose
创建闭包。 onClose
依次创建封闭creteria
对象,因为在时在creteria
对象中添加了新密钥。因此,onClose
调用时,只有添加新密钥时才存在的密钥。这样您就会看到奇怪的行为。
为解决问题,我建议在渲染期间仅将键存储在creteria
对象中,并将其封装在<div>
中。
注释中指出了另一个问题。您应该在creteria
中创建新的onClose
对象。否则,React不会更新creterai
,因为它仅使用Object.is
要解决此问题,请使用destruct运算符创建creteria
对象的新副本,像这样
const onClose = useCallback((key) => {
let newCreteria = { ...criteria };
delete newCreteria[key];
setCriteria(newCreteria);
}, [criteria])
useCallback
也没用。但是代码可以在其中正常工作。
工作示例为here
答案 1 :(得分:0)
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>
);
};