【问题标题】:Remove dynamic rendered element from dom in ReactJS从 ReactJS 中的 dom 中删除动态渲染元素
【发布时间】:2021-08-02 04:35:22
【问题描述】:

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

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>
      );
    });
  };

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

Rendered Component

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

有点像

{show ? renderCompoennt : null}

我尝试使用 vanilla 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 不允许我这样做。即使速度很快,每次删除一个项目时,react 都会抱怨“渲染的钩子更少”并导致应用程序崩溃。

【问题讨论】:

  • 你不能在地图中使用useState,我建议将地图中的内容提取为组件

标签: javascript reactjs dom-manipulation


【解决方案1】:

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

您的代码中的第一个问题和直接问题——它违反了rules of hooks,其中规定挂钩只能在顶层使用(决不能在循环、条件等内部)。

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

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

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

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

【讨论】:

    【解决方案2】:

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

    不要在循环、条件或嵌套函数中调用 Hooks。 相反,请始终在 React 函数的顶层使用 Hooks。经过 遵循此规则,您确保 Hooks 以相同的方式调用 每次渲染组件时排序。这就是让 React 能够 正确保留多个 useState 和 Hooks 之间的状态 useEffect 调用。

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

    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>
        );
    }
    

    【讨论】:

      猜你喜欢
      • 2020-10-09
      • 2015-07-16
      • 2020-03-24
      • 2020-08-20
      • 2018-03-10
      • 1970-01-01
      • 2014-09-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多