「完整FX」React18内核探秘:手写React高质量源码迈向高阶开发

React18内核探秘:手写React高质量源码迈向高阶开发

核心代码,注释必读

// download:3w ukoou com

React 和 ReactDOM 各自负责什么 react 负责描述特性,提供React API。

类组件、函数组件、hooks、contexts、refs...这些都是React特性,而 react 模块只描述特性长什么样、该怎么用,并不负责特性的具体实现。

react-dom 负责实现特性。

react-dom、react-native 称为渲染器,负责在不同的宿主载体上实现特性,达到与描述相对应的真实效果。比如在浏览器上,渲染出DOM树、响应点击事件等。

ReactDOM.render 的输入------ ReactElement

javascript 复制代码
import React from 'react';
import ReactDOM from "./ReactDOM";
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

上面是一段常见的 React 代码。在项目的入口,人为显示地调用ReactDOM.renderReactDOM.render 接受 "根组件实例"和"挂载节点",然后进行内部逻辑转换,最终将DOM树渲染到挂载节点上。

那么,ReactDOM.render拿到的 "根组件实例" 具体是什么?

组件实例其实是一个对象,以children属性关联组件的父子关系。由React.createElement函数创建。

ReactElement 是 React.createElement 的输出,ReactDOM.render的输入,是 react 和 react-dom 之间最直观的联系。那么,我们来扒一扒这个数据结构。

我们一般会用JSX来描述组件结构,JSX本质上是一种语法扩展,通过Babel编译最终生成下面的语句:

css 复制代码
React.createElement(
  type,
  [props],
  [...children]
)

JSX最终将对组件的描述转换为对React.createElement的调用。React.createElement做了什么?
React.createElement接受typepropschildren,然后进行一些操作:

  • 处理props,从props中提取出keyref
  • 处理children,将children以单体或者数组的形式附加到props
  • 返回一个符合 ReactElement 数据结构的对象

如果用TypeScript简单描述 ReactElement 数据结构,它长这样👇

**

typescript 复制代码
interface ReactElement {
  $$typeof: Symbol | number; // 标识该对象是React元素,REACT_ELEMENT_TYPE = symbolFor('react.element') || 0xeac7,用Symbol获得一个全局唯一值
  type: string | ReactComponent | ReactFragment
  key: string | null
  ref: null  | string | object
  props: {
    [propsName: string]: any
      children?: ReactElement | Array<ReactElement>
  },
  _owner: {
    current:  null | Fiber
  }
}

React18内核探秘:手写React高质量源码迈向高阶开发 - PureComponent应用案例

React.PureComponent 类似于我们常用的 React.Component,区别在于 PureComponent 的内置 shouldComponentUpdate 逻辑,它会同时对 propsstate 的变化前和变化后的值进行浅对比 ,如果都没发生变化则会跳过重渲染,相当于多了一层 props 对比;下面通过一个简单的例子来对比这两种组件的效果差异;

效果对比

假设有一个计数器,点击按钮增加计数,并用两种组件渲染计数值:

scala 复制代码
class Counter extends React.Component {
  state = { count: 0 };

  render() {
    const { count } = this.state;
    return (
      <div style=>
        <div>count: {count}</div>
        <CountText count={count > 2 ? count : 0} />
        <ConstText count={count > 2 ? count : 0} />
        <button onClick={() => this.setState({ count: count + 1 })}>Add</button>
      </div>
    );
  }
}

// 普通组件
class CountText extends React.Component {
  render() {
    const { count } = this.props;
    console.log('normal rendered', count);
    return <div>normal: {count}</div>;
  }
}

// "纯"组件
class ConstText extends React.PureComponent {
  render() {
    const { count } = this.props;
    console.log('pure rendered', count);
    return <div>pure: {count}</div>;
  }
}
javascript 复制代码
import React from './react';
import ReactDOM from './react-dom';

class Greeting extends React.PureComponent {
  render() {
    console.log("Greeting was rendered at", new Date().toLocaleTimeString());
    return <h3>Hello{this.props.name && ', '}{this.props.name}!</h3>;
  }
}

// const Greeting = React.memo(function Greeting({ name }) {
//   console.log("Greeting was rendered at", new Date().toLocaleTimeString());
//   return <h3>Hello{name && ', '}{name}!</h3>;
// });


class MyApp extends React.Component {
  constructor(props){
    super(props)
    this.state = {name: '', address: ''}
  }

  setName = (newName) => {
    this.setState({name: newName})
  }
  setAddress = (newAddress) => {
    this.setState({address: newAddress})
  }
  render(){
    return <div>
      <label>
        Name{': '}
        <input onInput={e => {
          this.setName(e.target.value)
        }} />
      </label>
      <label>
        Address{': '}
        <input onInput={e => {
          this.setAddress(e.target.value)
        }} />
      </label>
      <Greeting name={this.state.name} />
    </div> 
  };
}

ReactDOM.render(<MyApp />, document.getElementById('root'));
相关推荐
程序员码歌3 小时前
短思考第261天,浪费时间的十个低效行为,看看你中了几个?
前端·ai编程
Swift社区4 小时前
React Navigation 生命周期完整心智模型
前端·react.js·前端框架
若梦plus4 小时前
从微信公众号&小程序的SDK剖析JSBridge
前端
用泥种荷花4 小时前
Python环境安装
前端
Light604 小时前
性能提升 60%:前端性能优化终极指南
前端·性能优化·图片压缩·渲染优化·按需拆包·边缘缓存·ai 自动化
Jimmy4 小时前
年终总结 - 2025 故事集
前端·后端·程序员
烛阴5 小时前
C# 正则表达式(2):Regex 基础语法与常用 API 全解析
前端·正则表达式·c#
roman_日积跬步-终至千里5 小时前
【人工智能导论】02-搜索-高级搜索策略探索篇:从约束满足到博弈搜索
java·前端·人工智能
GIS之路5 小时前
GIS 数据转换:使用 GDAL 将 TXT 转换为 Shp 数据
前端
多看书少吃饭5 小时前
从Vue到Nuxt.js
前端·javascript·vue.js