1、浏览器是怎么认识JSX的?
javascript
function App () {
return <div>
hello world
<span>jsx是什么</span>
</div>
}
这是一个我们通过JSX语法写的一个App 组件,但是这并不是一个js代码,所以浏览器并不识别这段代码,也就无法在浏览器上渲染出来,所以就需要通过babel把它编译成浏览器识别的js代码
php
var _reactJsxRuntime = require("react/jsx-runtime");
function App() {
return /*#__PURE__*/ _reactJsxRuntime.jsxs("div", {
children: [
"hello world",
/*#__PURE__*/ _reactJsxRuntime.jsx("span", {
children: "jsx\u662F\u4EC0\u4E48"
})
]
});
}
由代码可以看出,JSX最终由babel编译成了一个_jsxs()_reactJsxRuntime.jsxs方法的调用,从而将组件代码转化为可以执行的js代码。
2、在react源码中是怎么处理JSX的?
在react源码中,暴露了jsx方法,这个方法接收3个参数,最终返回了一个ReactElement方法的调用
而这个ReactElement方法最终返回了一个element对象
所以在React中,jsx的本质上就是ReactElement方法调用的方式,创建出来一个与之对应的element对象,这个对象包含$$typeof type key ref props等属性。
3、JSX是什么?
JSX就是JavaScript的一种语法扩展,是描述UI的一种方法,最终会以React.createElement()或者是jsx()方法执行的方式展现,返回一个ReactElement对象,在react17版本之后如果不使用其他react API就可以不用引入React,因为react官方和babel官方进行了合作,可以直接通过react/jsx-runtime直接进行转换。
4、实现React.createElement方法
最终返回一个element对象,所以先写ReactElement方法,构造一个element对象,也就是React元素
typescript
const supportSymbol = typeof Symbol === 'function' && Symbol.for // 判断当前宿主环境是否支持Symbol
export const REACT_ELEMENT_TYPE = supportSymbol ? Symbol.for('react.element') : 0xeac7
/**
* ReactElement构造函数
* @param type
* @param key 组件的key
* @param ref 组件的ref
* @param props 组件的props
*/
const ReactElement = (type, key, ref, props) => {
const elelment = {
$$typeof:REACT_ELEMENT_TYPE, // 通过这个属性来指明当前对象是ReactElement结构对象
type,
key,
ref,
props,
__mark: 'Apollo', // 用于区分真实React中的ReactElement对象
}
return element
}
由源码知道,ReactElement方法是在jsx方法中调用
kotlin
/**
*
* @param type 元素类型
* @param config 元素属性,包括key,不包括子元素children
* @param maybeChildren 子元素children
* @returns 返回一个ReactElement
*/
const jsx =(type, config, ...maybeChildren) => {
// reactElement 自身的属性
let key = null
let ref = null
// 创建一个空对象props,用于存储属性
const props = {}
// 遍历config对象,将ref、key这些ReactElement内部使用的属性提取出来,不应该被传递下去
for(const propName in config){
const val = config[propName]
if(propName === 'key'){
if(val !== undefinde){
key = '' + val
}
continue
}
if(propName === 'ref'){
if (val !== undefined) {
ref = val
}
continue
}
// 如果propName是config自己的属性 则赋值给props
if({}.hasOwnProperty.call(config, propName)){
props[propName] = val
}
const childrenLength = maybeChildren.length
if(childrenLength){
if(childrenLength === 1){
props.children = maybeChildren[0]
}else{
props.children = maybeChildren
}
}
}
return ReactElement(type, key, ref, props)
}
5、实现JSX方法
React.createElement方法和jsx方法的区别这里只体现在第三个参数上。
ini
/**
*
* @param type 元素类型
* @param config 元素属性
* @param maybeKey 可能的key值
* @returns 返回一个ReactElement
*/
const jsx = (type: ElementType, config: any, maybeKey: any) => {
// 初始化key和ref为空
let key = null;
let ref = null;
// 创建一个空对象props,用于存储属性
const props: Props = {};
// 遍历config对象,将ref、key这些ReactElement内部使用的属性提取出来,不应该被传递下去
for (const prop in config) {
const val = config[prop];
if (prop === "key") {
continue;
}
if (prop === "ref") {
if (val !== undefined) {
ref = val;
}
continue;
}
// 一般使用{...props}将所有属性都传递下去,所以摘除ref、key属性外需要被保存到props中
if ({}.hasOwnProperty.call(config, prop)) {
props[prop] = val;
}
}
// 将 maybeKey 添加到 key 中
if (maybeKey !== undefined) {
key = "" + maybeKey;
}
return ReactElement(type, key, ref, props);
};
6、jsx方法和createElement的区别
jsx函数和createElement函数都用于在React中创建虚拟DOM元素,但它们的语法和用法有所不同。jsx函数来自于React 17及更高版本中的新的JSX转换功能,称为"Runtime Automatic"。
1、语法和转换方式:jsx函数用于处理新的JSX转换方式,其语法更简洁。createElement函数用于处理传统的JSX转换方式
javascript
const element = <div className="container">Hello, world!</div>;
// 使用createElement转换后的代码如下
const element = React.createElement(
"div",
{ className: "container" },
"Hello, world!"
);
// 使用jsx函数(自动运行时)转换后的代码如下:
import { jsx as _jsx } from "react/jsx-runtime";
const element = _jsx("div", { className: "container", children: "Hello, world!" });
2、子元素和key值处理:jsx函数将子元素作为属性(children)传递,而createElement函数将子元素作为额外的参数传递。同时子元素上的key值在jsx函数中也会以第三个参数的形式传递,而在createElement函数中,则是存在于config第二个参数中。
php
// 在createElement函数中:
React.createElement("div", {className: "app", key: "appKey"}, "hello,app");
// 在jsx函数中:
import { jsx as _jsx } from "react/jsx-runtime";
_jsx("div", {className: "app", children: "hello,app"}, "appKey");
3、兼容性和版本:createElement函数在所有React版本中可用,而jsx函数仅在React 17及更高版本中提供。尽管React团队推荐使用新的JSX转换方式,但许多现有项目可能仍在使用createElement函数