从dom中删除不必要的元素,而无需对此元素进行操作

时间:2019-06-20 20:41:58

标签: reactjs dom react-hooks

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进行检查:

https://codesandbox.io

2 个答案:

答案 0 :(得分:1)

您犯了两个错误

  1. creteria对象中添加新键时,您在空间上创建了closure。这段代码

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

    不仅将<div>元素添加到creteria对象,而且使用函数onClose创建闭包。 onClose依次创建封闭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也没用。但是代码可以在其中正常工作。

工作示例为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>
  );
};