Wenzi

React 组件多次调用时如何区分不同的 div 容器

蚊子前端博客
发布于 2024/09/02 23:45
在 React 组件多次被调用时,经常需要区分出不同调用之间的 DOM 元素

我们在一些 React 项目中,经常会有一些类库,需要传入 DOM 元素或者该元素的选择器。那么在多次调用组件时,如何区分不同的 div 容器呢?

1. 从外部传入标识 #

我们在每次调用时,都从外部传入一个标识,通过这个标识来区分不同的 div 容器。

// 自定义组件
const MyComponent = ({ id }) => {
  useEffect(() => {
    const dom = document.getElementById(id);
    console.log(dom);
  }, []);

  return <div id={id}></div>;
};

// 调用时
const App = () => {
  return (
    <div>
      <MyComponent id="id-1" />
      <MyComponent id="id-2" />
      <MyComponent id="id-3" />
    </div>
  );
};

这种方式的好处是元素的标识是外部传入的,不会因为多次调用组件而改变,同时可控,当其他组件也需要到该 DOM 元素时,也能准确获取到。

但不太好的点是,传入的标识,需要开发者自己确保唯一性,否则会产生冲突。

2. 通过 useRef 获取 #

在 React 中,可以使用 useRef() 的 hook 来获取组件的 DOM 元素。

// 自定义组件
const MyComponent = () => {
  const domRef = useRef(null);

  useEffect(() => {
    // 当前指定的dom元素
    console.log(domRef.current);
  }, []);

  return <div ref={domRef}></div>;
};

// 调用时
const App = () => {
  return (
    <div>
      <MyComponent />
      <MyComponent />
      <MyComponent />
    </div>
  );
};

这种方式,useRef() 在组件多次调用时,都是互相隔离的,获取的只是当前组件中的 DOM 元素。感兴趣地可以看下文章React 中 useState 和 useRef 与全局变量的区别

3. 自增 id #

我们也可以通过自增的方式,生成一个唯一的 id。利用 useState() 只能通过 setState()修改数据的特性,可以在初始化时,生成一个唯一的 id。

let globalIndex = 0;

const MyComponent = () => {
  /**
   * 多次调用当前组件时,globalIndex会自增,并且只会在组件初始化时执行,
   * 此后组件再更新时,id是不会变的
   **/
  const [id] = useState(`id-${globalIndex++}`);

  useEffect(() => {
    console.log(id, document.getElementById(id));
  }, []);

  return <div id={id}></div>;
};

// 调用时
const App = () => {
  return (
    <div>
      <MyComponent />
      <MyComponent />
      <MyComponent />
    </div>
  );
};

输出结果:

id-0 <div id=​"id-0">​</div>​
id-1 <div id=​"id-1">​</div>​
id-2 <div id=​"id-2">​</div>​

同样地,这里的唯一 id,除了使用全局的自增计数器外,也可以使用其它的方式,如:uuidnanoid等。

4. 通过 useId 设置唯一 id #

React 16.14 版本中,新增了 useId() hook,用于生成一个唯一的 id。当组件多次调用时,生成的 id 也是互不冲突的。

// 使用 useId() 生成唯一id
const MyComponent = () => {
  const id = useId();

  return <div id={id}></div>;
};

// 调用时
const App = () => {
  return (
    <div>
      <MyComponent />
      <MyComponent />
      <MyComponent />
    </div>
  );
};

最终生成的 dom 元素是:

<div>
  <div id=":r0:"></div>
  <div id=":r1:"></div>
  <div id=":r2:"></div>
</div>

如果同一个组件中,需要生成多个不同的 id,可以多次调用 useId()

如果是在服务端渲染的场景中,最好是使用useId()的方案,React 能够保证在服务端和客户端生成的 id 是相同的。

若使用自增计数器的方式,随着 React Fizz(React 新的服务端流式渲染器)的到来,服务端渲染顺序和客户端挂载的顺序可能不再一致。导致服务端和客户端产生的 id 不一样。

若是使用时间戳或随机数等方式,更不可能在服务端和客户端生成相同的 id 了。

5. 总结 #

能够获取到当前组件的 DOM 元素,是 React 中一个非常常用的需求。大家可以根据不同的场景来使用不同的方式。

标签:reacthooks
阅读(107)
Simple Empty
No data