react替换元素节点_一道 React 面试题:在浏览器、组件和元素中都渲染了些什么?...

// 每日前端夜话 第403篇
// 正文共:1500 字
// 预计阅读时间:7 分钟
0d5d6e2392f57d980b53e88c8019c5d4.png

这道题的答案有点复杂。

首先要搞清楚 elementcomponent 是不是一回事?

从技术上来说,ReactDOM 不会在 DOM 中渲染 React 组件或 React 元素。它渲染由其组件实例支持的 DOM 元素。对于类组件来说这是正确的。但是对于函数组件,ReactDOM 仅渲染 DOM 元素。函数组件没有实例(可以通过 this 访问),因此在使用函数组件时,ReactDOM 会渲染由函数返回的元素所生成的 DOM 元素。

你需要在这里理解的是,React 元素不同于 DOM 元素。React 元素只是 HTML 元素、React 组件或它们的混合的“描述”。

好吧,一个更好的面试题可能应该这样问:当你在JSX中使用 之类的东西时,它是组件、元素还是实例?

这是一个元素,但不是 DOM 元素,而是一个 React元 素。因为任何 JSX 标签都会被转换为 React.createElement 再去调用。

但是要想让 React 继续使用这个 React 元素的话,必须调用一个函数或从一个类中创建实例。

你可能会在一些 React 教程中看到 组件(component)、元素(element)实例(instance) 这些词。我在这里混用这些词是不对的,但是我认为 React 的初学者需要了解它们的区别。React 官方博客上有一篇文章专门说明这些概念,但我认为这些内容对于初学者来说还远远不够。

以下是这些术语的简单定义:

  • React Component 是模板,蓝图,全局定义的。可以是函数(带有渲染功能)。
  • React Element 是从组件中返回的东西。这个对象实际上描述了组件所代表的 DOM 节点。对于函数组件来说,此元素是函数返回的对象。对于类组件,元素是组件的渲染函数返回的对象。React 元素不是我们在浏览器中所看到的。它们只是内存中的对象,我们无法对其进行任何更改。
  • React 在其内部通过创建、更新和销毁 instance 来找出需要渲染给浏览器的 DOM 元素树。使用类组件时,通常将其浏览器渲染的 DOM 元素称为组件实例。你可以渲染同一组件的多个实例。实例是你在基于类的组件内部使用的 this 关键字。你不需要手动从类创建实例,只需要记住它就在 React 的内存中即可。
  • 基于函数的 React 元素没有实例。一个函数组件仍然可以被多次渲染,但是 React 不会将本地实例与每个渲染相关联。它只是用函数的调用来确定要为该函数渲染的 DOM 元素。

最重要的是,ReactDOM 不会在浏览器中渲染组件,也不会渲染元素(这里的术语元素代表 React.createElement 的返回值)。它也不渲染实例。它只渲染 DOM 元素。

不幸的是,使用术语组件既指模板又指通过模板使用的任何一种实例或者调用,这似乎是很普遍的。人们对此感到困惑很正常,这挺痛苦的。

每个 React 应用都从一个使用 React elementrender 调用开始。下面以 reactjs.org 官网提供的 HelloMessage 案例作为例子,我对这个例子稍微做了一些修改,使其具有了函数组件:

const Today = () => (
  <div>Today is {new Date().toDateString()}div>
);class HelloMessage extends React.Component {
  render() {
    return (
      <React.Fragment><div>Hello {this.props.name}div><Today />React.Fragment>
    );
  }
}ReactDOM.render(
  <HelloMessage name="Taylor" />,
  mountNode
);

第一个 React 元素是我们在 ReactDOM.render 调用中开始的元素:

<HelloMessage name="Taylor" /> // 这是 React element

这个 React 元素描述了要渲染的 DOM 树应该以 HelloMessage 组件和值等于 Taylor 的 prop name 开始。

现在回答问题:HelloMessage 是什么?

每当 React 元素描述一个 React 组件时(就像上面的 React 元素一样),React 使用该组件将描述替换为组件返回的内容。这时它将会为基于类的组件创建一个实例,并将该实例的引用保留在内存中。它不会为基于函数的组件创建任何内容。它只是调用它们。

HelloMessage 组件返回的是一个描述 React.Fragment 组件的 React 元素。

回答问题:React.Fragment 是什么?

React 会持续不断的减少这些组件的未知描述,直到只存在有效的 DOM 节点。React.Fragment 的描述被翻译成 2 个React 元素,一个描述 div ,另一个描述 Today 组件。

回答问题:代码中的 Today  什么是?

它调用 Today 函数来找出最后一个问题。Today 函数返回描述一个 div 的 React 元素。

至此,virtual 树中包含了所有描述 DOM 节点的 React 元素。React 通过一致性比较算法找出要在浏览器中更新的内容。用组件实例所转换的树节点保留修改该实例的能力。


bf900e78bfb396f94e67bbb671683ac2.gif
359ef06eba0ff3422da8fbb5ba253418.png
精彩文章回顾,点击直达
aa1567b5253098adcf97cc0b9eb5baba.png 前端先锋

长按扫描维码
关注我们 获取更多前端资讯
|最新技术|业界动态|

|学习视频|源码资源|

前端先锋 d0eaee1697f01d48961f2529e3a4fbcc.gif转了吗 affb29e6d3ef72a1f4f9dceb5ac32228.gif赞了吗 67aaddc2c1ea87c02d3ac6f6a86d22d6.gif在看吗
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值