React同步从DOM中移除一个元素

huangapple go评论74阅读模式
英文:

React synchronously remove an item from the dom

问题

I need to synchronously remove a child from the container. I created a simplified code to show my current solution (Which makes use of normal pattern using useState hook)

type ChildProps = {
  index: number;
  id: string;
  remove: (index: number) => void;
};

function Child(props: ChildProps) {
  const handleClick = () => {
    console.log('FIRST');
    props.remove(props.index);
    console.log('THIRD');
  };
  return (
    <button id={props.id} onClick={handleClick}>
      Child {props.index}
    </button>
  );
}

export default function Home() {
  const [childrens, setChildrens] = React.useState<{ el: React.ReactNode; index: number }[]>([]);

  const removeChildren = (index: number) => {
    setChildrens((old) => old.filter((e) => e.index !== index));
  };

  const addChildren = () => {
    const index = new Date().getTime();
    setChildrens((old) => [
      ...old,
      { index, el: <Child id={`${index}`} index={index} remove={removeChildren} /> },
    ]);
  };

  console.log('SECOND');
  return (
    <div>
      <button onClick={addChildren}>Add</button>
      <div>{childrens.map((e) => e.el)}</div>
    </div>
  );
}

当调用删除处理程序时,首先打印出"FIRST",然后调用删除函数(该函数会触发父组件的状态更新),然后打印出"THIRD",最后,当父组件更新时,将打印出"SECOND",这将“删除”子组件。

我需要在调用删除方法后的下一条指令中删除组件。

在我的应用程序中,我在子组件中使用Tanstack Query hooks来使用来自API的数据。

在调用删除端点之后,我删除了组件并使缓存无效。

问题是,缓存在组件卸载之前被使无效,这会导致调用端点以获取组件数据(因为Tanstack hook仍然处于活动状态,因为组件仍然存在于DOM中),这会导致端点调用中出现错误,因为条目不再存在。

我尝试寻找一种方式来操作React虚拟DOM,但没有找到有用的方法。

直接操作DOM不是一个好的选择

document.getElementById(`${index}`)?.remove()

这会导致以下异常:
Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node

英文:

I need to synchronously remove a child from the container. I created a simplified code to show my current solution (Which makes use of normal pattern using useState hook)

type ChildProps = {
  index: number;
  id: string;
  remove: (index: number) => void;
};

function Child(props: ChildProps) {
  const handleClick = () => {
    console.log('FIRST');
    props.remove(props.index);
    console.log('THIRD');
  };
  return (
    <button id={props.id} onClick={handleClick}>
      Child {props.index}
    </button>
  );
}

export default function Home() {
  const [childrens, setChildrens] = React.useState<{ el: React.ReactNode; index: number }[]>([]);

  const removeChildren = (index: number) => {
    setChildrens((old) => old.filter((e) => e.index !== index));
  };

  const addChildren = () => {
    const index = new Date().getTime();
    setChildrens((old) => [
      ...old,
      { index, el: <Child id={`${index}`} index={index} remove={removeChildren} /> },
    ]);
  };

  console.log('SECOND');
  return (
    <div>
      <button onClick={addChildren}>Add</button>
      <div>{childrens.map((e) => e.el)}</div>
    </div>
  );
}

When the remove handler is called, FIRST is printed, then the remove function is called (which dispatches the parent component's status update), then THIRD is printed, and finally SECOND will be printed when the parent component is updated which will "remove" the child.

I need the component to be removed on the next instruction after the removal method call.

In my application in the child components I make use of Tanstack Query hooks to use the data from the api.

After calling a delete endpoint I delete the component and invalidate the cache.

The problem is that the cache is invalidated before the component is unmounted and this causes the endpoint to be called to get the component data (because the Tanstack hook is still active since the component is still present in the DOM) this causes an error in the endpoint call as the entry no longer exists.

I've tried looking for ways to manipulate the react virtual DOM but haven't found anything useful.

Manipulating the DOM directly is not a good option

document.getElementById(`${index}`)?.remove()

This causes the following exception:
Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node

答案1

得分: 1

我在React的新文档中找到了答案。

> 要解决这个问题,你可以强制React同步更新(“刷新”)DOM。为此,导入react-dom中的flushSync,并将状态更新包装在flushSync调用中。

文档链接

英文:

I found the answer into React new docs.

> To fix this issue, you can force React to update (“flush”) the DOM synchronously. To do this, import flushSync from react-dom and wrap the state update into a flushSync call

Link to the doc

huangapple
  • 本文由 发表于 2023年2月19日 23:57:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/75501405.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定