React源码解析-JSX

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: React源码解析-JSX

React是世界上最好的前端工程师们历经多年打造的UI库
他的宗旨是:learn once, write anywhere
得益于优秀的设计,react可以开发:

web
native app
vr
桌面应用
3d应用

在每个平台上,我们都可以使用JSX
一. 什么是JSX
JSX是js的一种扩展,也是一种表达式。 React认为渲染逻辑 本质上 与 UI 是耦合的。
javascript复制代码const App =


您好

显然浏览器,是不认识的,这个时候,我们需要babel
二. transform JSX
preset-react
preset-react是babel在react下的解决方案
preset-react包会包含以下3个包:

@babel/plugin-syntax-jsx
让babel认识jsx语法

@babel/plugin-transform-react-jsx
转化jsx为函数调用
需要注意的是jsx并不是只能被编译成createElement函数,此插件可以自由配置

@babel/plugin-transform-react-display-name
处理react class displayName

旧版jsx转换
先看个🌰:
js复制代码function App() {
return

1

}

export default App;

当我们运行时,会报错:React is not defined。(内心一万匹马在奔腾)

在react17之前,jsx转换都会转换为React.createElement调用, 所以我们必须在第一行加上:
js复制代码import React from "react"

新版jsx转换
17版本之后,react升级了支持了jsx runtime,从此我们再也不需要担心 react is not defined
转化前代码:
js复制代码function App() {
return

1

}

转化后代码:
js复制代码import { jsx } from 'react/jsx-runtime';

function App() {
return jsx("div", { children: "1" })
}

注意:不要手动引入 import { jsx } from "react/jsx-runtime"
transform result
本质上,react中的jsx会转化为createElement 或者 jsx函数调用。
我们以createElement为例,先看源码方法定义:
js复制代码function createElement(type, config, children) {
// ...
}

为了了解入参,我们先看几个🌰:

  1. 单一元素
    jsx:
    html复制代码

    hello world

结果:
js复制代码React.createElement(
"div",
{
"data-id": "test-id"
},
"hello world"
);

  1. 嵌套标签
    jsx:
    html复制代码

    hello world

    hello span

结果:
js复制代码React.createElement(
"div",
{
"data-id": "test-id"
},
"hello world",
React.createElement(
"span",
{
className: "span"
},
"hello span"
)
);

不难发现,createElement方法只定义了3个参数,而本次转化结果 顶层createElement方法 有4个参数,为什么呢? 其实createElement后面可以写n个参数,内部会使用arguments对象做children集合。这个我们后面分析createElement源码再聊。

  1. 组件标签
    jsx:
    html复制代码

    hello world

    hello span


结果:
js复制代码React.createElement(
"div",
{
"data-id": "test-id"
},
"hello world",
React.createElement(
"span",
{
className: "span"
},
"hello span"
),
React.createElement(TestComponent, {
name: "trump"
})
);

由此可看出,createElement第一个参数type,可以是div, span,也可以是Component。
jsx -> createElement过程的源码实现,我们后面单独开章节分析,总的概括是 AST -> Optimize -> Generate createElement,17版本之前之前和之后做了较大的改动。
这里,我们只要记住,babel利用相关插件,将jsx转化为一系列函数调用,若不指定jsx runtime,默认使用createElement函数调用,反之jsx函数调用
三. createElement
核心代码
js复制代码function createElement(type, config, children) {
// ...
const props = {};
let key = null;
let ref = null;

// 将config属性赋值给props
...
// 处理childrens,可以传入n个参数
const childrenLength = arguments.length - 2;
if(childrenLength === 1) {
// 只有1个children直接赋给props
props.children = children
}else (childrenLength > 1) {
// 利用arguments对象将多个children,依次循环组装成一个childrens数组
// 将childrens数组挂载到props对象上
...
}

// 处理组件的defaultProps,如果props上对应的key不存在,那么使用defaultProps值
// 注意props可以是函数组件,可以是div,可以是class component
if (type && type.defaultProps) {
const defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}

return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
}

说明
总的来说,createElement函数,做一些初始化工作,定义props,挂载key, ref, children,处理defaultProps,最后返回ReactElement函数调用。
四. ReactElement
核心代码
js复制代码function ReactElement(type, key, ref, self, source, owner, props) {
const element = {
$$typeof: REACT_ELEMENT_TYPE, type: type, key: key, ref: ref, props: props, _owner: owner, }; // dev环境的处理,主要解决element对象的_self, _source属性不可以写,另外冻结element和props // ... return element; } 对象说明 reactElement会返回一个元素对象,其中: $$typeof: 是一个Symbol,为了防止xss攻击而设置(因为json不支持symbol)
type: 元素类型,可以是div,可以是函数组件,可以是类组件
key: props传入的key
ref: props传入的ref
props: 属性
_owner: 记录负责创建这个元素的组件,类型后期实际是个Fiber

五. 总结
jsx本质上是描述元素的一种数据结构,最终将被babel转化为createElement函数或jsx函数调用,最后返回element对象。他本身不包括组件的state, 也不包括lane模型,不包括调和阶段信息
jsx在babel层面的解析,我将在后面的章节单独分享。下面的文章,我们开启react源码解析之旅吧~ 标签: React.js

作者:GW_刘振
链接:https://juejin.cn/post/7084958413284704292
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

目录
相关文章
|
3月前
|
前端开发 JavaScript
React 步骤条组件 Stepper 深入解析与常见问题
步骤条组件是构建多步骤表单或流程时的有力工具,帮助用户了解进度并导航。本文介绍了在React中实现简单步骤条的方法,包括基本结构、状态管理、样式处理及常见问题解决策略,如状态管理库的使用、自定义Hook的提取和CSS Modules的应用,以确保组件的健壮性和可维护性。
89 17
|
5月前
|
前端开发 JavaScript
React Hooks 全面解析
【10月更文挑战第11天】React Hooks 是 React 16.8 引入的新特性,允许在函数组件中使用状态和其他 React 特性,简化了状态管理和生命周期管理。本文从基础概念入手,详细介绍了 `useState` 和 `useEffect` 的用法,探讨了常见问题和易错点,并提供了代码示例。通过学习本文,你将更好地理解和使用 Hooks,提升开发效率。
126 4
|
18天前
|
Web App开发 监控 前端开发
React音频播放控制组件开发深度解析
本文介绍了构建React音频控制组件时遇到的关键问题及优化方案。主要包括: 1. **状态同步难题**:解决播放按钮与音频状态不同步的问题,通过双向绑定机制确保一致。 2. **跨浏览器兼容性**:处理Safari和Chrome预加载策略差异,确保`duration`属性正确获取。 3. **进度控制优化**:避免使用`setInterval`,采用`requestAnimationFrame`提升性能;优化拖拽交互,防止音频卡顿。 4. **音量控制进阶**:实现渐变音量调节和静音状态同步。
63 15
|
5月前
|
前端开发
深入解析React Hooks:构建高效且可维护的前端应用
本文将带你走进React Hooks的世界,探索这一革新特性如何改变我们构建React组件的方式。通过分析Hooks的核心概念、使用方法和最佳实践,文章旨在帮助你充分利用Hooks来提高开发效率,编写更简洁、更可维护的前端代码。我们将通过实际代码示例,深入了解useState、useEffect等常用Hooks的内部工作原理,并探讨如何自定义Hooks以复用逻辑。
|
5月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
404 2
|
3月前
|
前端开发 UED
React 文本区域组件 Textarea:深入解析与优化
本文介绍了 React 中 Textarea 组件的基础用法、常见问题及优化方法,包括状态绑定、初始值设置、样式自定义、性能优化和跨浏览器兼容性处理,并提供了代码案例。
115 8
|
4月前
|
JavaScript 前端开发 容器
React零基础入门02--JSX语法基础
React零基础入门02--JSX语法基础
React零基础入门02--JSX语法基础
|
4月前
|
XML 前端开发 JavaScript
react之了解jsx
react之了解jsx
|
4月前
|
前端开发 JavaScript
React Hooks 深入解析
React Hooks 深入解析
50 0
|
5月前
|
XML 前端开发 JavaScript
React JSX
React 使用 JSX(一种类似 XML 的 JavaScript 语法扩展)来替代传统 JavaScript 编写 UI。JSX 使代码更简洁、执行更快且类型安全。例如,`<h1>Hello, world!</h1>` 实际上是创建一个 React 元素,通过 `ReactDOM.render()` 渲染到 DOM。注意,JSX 中使用 `className` 替代 HTML 的 `class` 属性。

推荐镜像

更多