React是如何渲染元素和组件的

元素的概念

元素是构成 React 应用的最小单位。元素描述了你在屏幕上想看到的内容。React 元素是创建开销极小的普通对象。React DOM 会负责更新 DOM 来与 React 元素保持一致。

将一个元素渲染为 DOM

假设我们的 HTML 文件有一个根元素 <div>该节点内的所有内容都将由 React DOM 管理

js 复制代码
<div id="root"></div>

注意: React 构建的应用通常只有单一的根 DOM 节点,如果你想要将 React 集成进一个已有搭建好的应用,那么你可以在应用中包含任意多的独立根 DOM 节点。

将一个 React 元素渲染到根 DOM 节点中,只需把它们一起传入 ReactDOM.render():

js 复制代码
// 已有的应用
<div> 
<h1>Existing App</h1> 
<div id="root1"></div> 
<div id="root2"></div>
</div>
js 复制代码
import ReactDOM from 'react-dom';
// React 组件
const element1 = <h1>Hello, world</h1>;
const element2 = <h1>Hello, world</h1>;
ReactDOM.render(element1, document.getElementById('root1'));
ReactDOM.render(element2, document.getElementById('root2'));

更新已渲染的元素

React 元素是不可变对象。一旦创建,React 元素的子元素和属性就不能直接更改

时钟组件示例:

js 复制代码
    class Clock extends React.Component {
      constructor(props) {
        super(props);
        this.state = {date: new Date()};
      }

      componentDidMount() {
        this.timerID = setInterval(
        //组件挂载到 DOM 后,每一秒调用一次tick()方法
          () => this.tick(),
          1000
        );
      }

      componentWillUnmount() {
        clearInterval(this.timerID);
      }

      tick() {
        this.setState({
       //使用 `setState` 方法更新组件的状态,将 `date` 属性更新为当前时间的 `Date` 对象 
          date: new Date()
        });
      }

      render() {
        return (
          <div>
            <h1>Hello, world!</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
          </div>
        );
      }
    }

    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(<Clock />);

代码分析:

  1. 首先,我们定义了一个名为 Clock 的类,它继承了 React.Component。
  2. 在构造函数中,我们初始化了组件的状态(state),其中 date 属性被设置为当前时间的 Date 对象。
  3. 在组件挂载到 DOM 后,componentDidMount 生命周期方法会被调用。在这个方法中,我们创建了一个定时器,并将定时器的 ID 存储在组件的实例变量 timerID 中。定时器每秒触发一次 tick 方法。
  4. tick 方法被调用时,它会使用 setState 方法更新组件的状态,将 date 属性更新为当前时间的 Date 对象。通过调用 setState,React 会检测到状态的变化,并触发重新渲染。
  5. render 方法定义了组件的渲染逻辑。它返回一个包含两个 <h1> 和 <h2> 元素的 <div>。其中 <h1> 显示 "Hello, world!",而 <h2> 则显示当前时间,通过访问组件的状态中的 date 属性来获取时间,并使用 toLocaleTimeString 方法将其格式化为本地时间字符串。
  6. 最后,我们使用 ReactDOM.createRoot 创建一个根节点,并将 <Clock /> 组件传递给 root.render 方法,以将组件渲染到指定的根节点上。

这里的生命周期 componentWillUnmount()和 componentDidMount()以及State后面会讲到

注意: 在实践中,大多数 React 应用只会调用一次 ReactDOM.render()。

函数组件与 class 组件

React定义组件的方式主要有两种,函数组件(目前主流)和class组件

函数式组件示例:

复制代码
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

接收唯一带有数据的 "props"(代表属性)对象与并返回一个 React 元素。这类组件被称为"函数组件"

class组件示例

复制代码
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

使用自定义组件方式:

复制代码
const element = <Welcome name="zayyo" />;

当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)以及子组件(children)转换为单个对象传递给组件,这个对象被称之为 "props"。在上面的示例中name的值"zayyo"就是组件中的的props.name获取到的值。

过程:

  • 我们调用 root.render() 函数,并传入 <Welcome name="zayyo" /> 作为参数。
  • React 调用 Welcome 组件,并将 {name: 'zayyo'} 作为 props 值传入。
  • Welcome 组件将 <h1>Hello, zayyo</h1> 元素作为返回值。
  • React DOM 将 DOM 高效地更新为 <h1>Hello, zayyo</h1>。

注意: 组件名称必须以大写字母开头 。因为React 会将以小写字母开头的组件视为原生 DOM 标签。例如,<div /> 代表 HTML 的 div 标签,而 <Welcome /> 则代表一个组件,并且需在作用域内使用 Welcome。

组合组件

我们可以使用多个自定义组件来组成我们的页面。

在下面的代码示例中,将会渲染三个 Welcome 组件,分别显示 "Hello, z"、"Hello, A" 和 "Hello, Y":

js 复制代码
    function Welcome(props) {
      return <h1>Hello, {props.name}</h1>;
    }

    function App() {
      return (
        <div>
          <Welcome name="z" />      
          <Welcome name="A" />     
          <Welcome name="Y" />    
         </div>
      );
    }
    ReactDOM.render(<App />, document.getElementById('root'));

在上面,我们使用 <Welcome name="z" />、<Welcome name="A" /> 和 <Welcome name="Y" /> 分别创建了三个 Welcome 组件的实例,并将它们放置在 <div> 中。

每个 Welcome 组件都会接收不同的 name 属性值,通过 props.name 来访问该属性值,并在组件内部的 <h1> 元素中渲染相应的问候消息。

相关推荐
LucianaiB6 小时前
【元宝搜索开发者征文大赛】AI时代,学得慢就不用学?用元宝搜索打造一个教程保质期,确保每一个教程符合你的现状
前端·人工智能·ai编程
excel6 小时前
JavaScript 对象池:减少高频对象创建与 GC 压力
前端
陈随易8 小时前
纯 Go 写的 JS 引擎,跑分超过了 C 语言的 QuickJS
前端·后端·程序员
子兮曰10 小时前
Chrome 权限元素实战:144 与 151 的渐进增强写法
前端·javascript·chrome
IT_陈寒10 小时前
Redis连接池泄漏那次,我差点把生产环境搞崩了
前端·人工智能·后端
强尼银手10 小时前
我花一天做了个格斗游戏原型,判定全对,然后被「美术」劝退了
前端·javascript
石小石Orz10 小时前
AI 正在蚕食我们的编码能力
前端·后端·算法
陈随易11 小时前
专注飞机 FocusFlight,两个人把番茄钟做成了一趟航班
前端·后端·程序员
总要学点什么11 小时前
第98篇:三维特效-材质线效果——给一条线换十种材质,虚线的图案只填了一半
开发语言·前端·javascript·ecmascript·gis·webgl·材质
10share12 小时前
基于大模型的 i18n 方案:把中文原文当 Key,轻松搞定多语言维护
前端·vue.js