繁体   English   中英

从 ReactJS 中的 dom 中删除动态渲染元素

[英]Remove dynamic rendered element from dom in ReactJS

目前我有一个看起来像这样的反应组件:

const GeraCard = (cards, cart = false) => {
    return cards.map((v, i) => {
      return (
        <div key={i} className={styles.card}>
          <div onClick={() => urlRender(v.url)} className={styles.cardContent}>
            <div>
              <span className={styles.cardTitulo}>{v.Nome}</span>
            </div>
            <div>
              <span className={styles.cardData}>{v.Data}</span>
              <span className={styles.cardAtivos}>{v.Ativos} ativo(s)</span>
            </div>
            {cart ? <div>R$ {FormatCapital(v.Capital)}</div> : null}
          </div>
          <span className={styles.trash}>
            <FontAwesomeIcon
              icon={faTrash}
              color={"#3c3c3c77"}
              onClick={(e) => {
                e.persist()
                TrashHandler(v.Nome, e)
              }}
            />
          </span>
        </div>
      );
    });
  };

基于卡片数组,它呈现如下内容:

渲染组件

每当我单击垃圾桶按钮时,我都会向后端发出请求,编辑数据库中的列表并根据现在更新的“卡片”重新呈现组件。 问题是这需要一段时间才能发生,所以我想要一种方法在我的后端完成它的工作时立即从 dom 中删除它。

有点像

{show ? renderCompoennt : null}

我尝试使用香草 javascript 从垃圾桶中抓取父级,这将是我要删除的卡,但结果无法预测,而且速度也很慢。

我最近的尝试是这样的:

const GeraCard = (cards, cart = false) => {
    return cards.map((v, i) => {
      const [show, setShow] = useState(true);
      return (
        <div key={i}>
          {show ?
            <div className={styles.card}>
              <div onClick={() => urlRender(v.url)} className={styles.cardContent}>
                <div>
                  <span className={styles.cardTitulo}>{v.Nome}</span>
                </div>
                <div>
                  <span className={styles.cardData}>{v.Data}</span>
                  <span className={styles.cardAtivos}>{v.Ativos} ativo(s)</span>
                </div>
                {cart ? <div>R$ {FormatCapital(v.Capital)}</div> : null}
              </div>
              <span className={styles.trash}>
                <FontAwesomeIcon
                  icon={faTrash}
                  color={"#3c3c3c77"}
                  onClick={(e) => {
                    setShow(false);
                    e.persist()
                    TrashHandler(v.Nome, e)
                  }}
                />
              </span>
            </div> :
            null
          }
        </div>
      );
    });
  };

但反应不会让我这样做。 即使它很快,每次删除一个项目时,react 都会抱怨“渲染的钩子更少”并使应用程序崩溃。

有谁知道解决方法? 谢谢!

您正在尝试做一些Optimistic UI ,其中您假设您的操作将成功,并在对后端的请求完成之前立即反映预期/假设的 state。 这将代替显示一些进度/忙碌指示器,如微调器,直到服务器完成操作。

您的代码中的第一个问题和直接问题 - 它违反了hooks 的规则,即 Hooks 只能在顶层使用(永远不要在循环、条件等)中使用。

第二个问题是您正在利用 vanilla JS 直接操作 DOM; 这通常是 MV* 框架中的反模式,在这里也是如此。 相反,我建议在您的数据 model 中进行管理; 像这样的东西:

  1. 如果卡具有已deleted的属性,则重写您的.map处理程序以返回null
  2. 当用户点击垃圾桶按钮时,做两件事:
    1. 向后端发出请求以删除它
    2. 使用setStatedeleted: true属性添加到点击的卡片

现在,您将获得一个忽略已删除卡的重新渲染,并向后端发出请求,所有这些都在 React 数据 model 中。 确保您处理以下复杂性:

  1. 如何处理响应
  2. 后台删除失败如何处理错误
  3. 如果用户在任何请求完成之前快速单击许多卡片进行删除,如何进行管理。

祝你好运,编码愉快!

问题是,在第一次渲染中,您有 {cards.length} 调用来挂钩 GeraCard 中的“useState”,但在删除一张卡片后,您将有 {cards.length-1} 调用来挂钩“useState”。 作为 React 文档 state:

不要在循环、条件或嵌套函数中调用 Hook。 相反,请始终在 React function 的顶层使用 Hooks。 通过遵循此规则,您可以确保每次渲染组件时都以相同的顺序调用 Hook。 这就是允许 React 在多个 useState 和 useEffect 调用之间正确保留 Hooks 的 state 的原因。

您应该将 map 回调的内容提取到单独的组件中。

const GeraCards = (cards, cart = false) => {
    return cards.map((v, i) =>
        <GeraCard card={v} index={i} cart={cart} />
    );
};

const GeraCard = ({ card, index, cart }) => {
    const [show, setShow] = useState(true);
    const v = card;
    return (
        <div key={index}>
            {show ?
                <div className={styles.card}>
                    <div onClick={() => urlRender(v.url)} className={styles.cardContent}>
                        <div>
                            <span className={styles.cardTitulo}>{v.Nome}</span>
                        </div>
                        <div>
                            <span className={styles.cardData}>{v.Data}</span>
                            <span className={styles.cardAtivos}>{v.Ativos} ativo(s)</span>
                        </div>
                        {cart ? <div>R$ {FormatCapital(v.Capital)}</div> : null}
                    </div>
                    <span className={styles.trash}>
                        <FontAwesomeIcon
                            icon={faTrash}
                            color={"#3c3c3c77"}
                            onClick={(e) => {
                                setShow(false);
                                e.persist()
                                TrashHandler(v.Nome, e)
                            }}
                        />
                    </span>
                </div> :
                null
            }
        </div>
    );
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM