惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
G
Google Developers Blog
B
Blog RSS Feed
A
About on SuperTechFans
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
V2EX
Stack Overflow Blog
Stack Overflow Blog
C
Check Point Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Engineering at Meta
Engineering at Meta
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - 司徒正美
D
Docker
F
Fortinet All Blogs
Hugging Face - Blog
Hugging Face - Blog
Last Week in AI
Last Week in AI
H
Help Net Security
WordPress大学
WordPress大学
MyScale Blog
MyScale Blog
博客园 - Franky
人人都是产品经理
人人都是产品经理
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Blog — PlanetScale
Blog — PlanetScale
L
LangChain Blog

蚊子的前端博客

微说 | 有的人觉得只要不考XX,一定能考好!-蚊子的前端博客 微说 | 春天来了-蚊子的前端博客 明天和意外不知道哪个先来-蚊子的前端博客 微说 | 既然错过了路口,就及时止损,重新规划路线上路-蚊子的前端博客 微说 | 2025年的出生人口数是792万-蚊子的前端博客 微说 | 工作年终总结,让写对接的接口的数量?-蚊子的前端博客 微说 | 温家宝:没有政治体制改革的成功 经济体制改革不可能进行到底-蚊子的前端博客 微说 | 违法犯罪了该不该被禁言?-蚊子的前端博客 微说 | 不明白为什么在推荐去俄罗斯旅游-蚊子的前端博客 微说 | 易中天论骗子-蚊子的前端博客 微说 | 一场大风吹散了秋天-蚊子的前端博客 微说 | 既要、又要、还要、更要!-蚊子的前端博客 又是一年的国庆雨季-蚊子的前端博客 微说 | 预估下2025年的出生人口数据-蚊子的前端博客 微说 | 可惜了我那些小时候的书本-蚊子的前端博客 微说 | 牛马有的是,驴不够了!-蚊子的前端博客 微说 | 能否有一条非户口也能高考的路-蚊子的前端博客 微说 | 小聊中医-蚊子的前端博客 微说 | 将要制作的一款新产品-蚊子的前端博客 微说 | 做人要有信-蚊子的前端博客 微说 | 好一个正义联盟-蚊子的前端博客 微说 | 都是见过吃过的主儿-蚊子的前端博客 微说 | 追求8小时工作制有错吗?-蚊子的前端博客 微说 | 如果尖锐的批评完全消失-蚊子的前端博客 微说 | 很好!-蚊子的前端博客 微说 | 封禁用户可以,但要告知具体原因-蚊子的前端博客 微说 | 面朝大海,春暖花开-蚊子的前端博客 微说 | 程序员的悲哀是什么?-蚊子的前端博客 微说 | 2025年出生人口的预测-蚊子的前端博客 前端在 LiveKit 中如何获取所有的参与者-蚊子的前端博客
React 组件多次调用时如何区分不同的 div 容器-蚊子的前端博客
author · 2024-09-02 · via 蚊子的前端博客

我们在一些 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 中一个非常常用的需求。大家可以根据不同的场景来使用不同的方式。