原理简化了解
import React from "react"
import { createRoot } form "react-dom/client"
const element = React.createElement(
'p',
{id: 'hello'},
'Hello World!'
)
const container = document.querySelector('#root')
const root = createRoot(container)
root.render()
编写一个自定义的render函数,该函数接受“React元素”和对container的引用:
function render(reactElement, containerDOMElement) {
// 创建一个DOM对象
const domElement = document.createElement(reactElement.type)
// 更新属性
domElement.innerHTML = reactElement.children;
for (const key in reactElement.props) {
const value = reactElement.props[key];
domElement.setAttribute(key, value);
}
// 添加为子节点
containerDOMElement.appenChild(domElement)
}
const reactElement = {
type: 'a',
props: {
href: 'https://wikipedia.org/',
id: 'some-links',
'data-num': 20,
},
children: 'Read more on Wikipedia',
};
const containerDOMElement =
document.querySelector('#root');
render(reactElement, containerDOMElement);
expression slots
我们可以使用大括号 ( {}
) 创建expression slots,任何放在大括号之间的内容都将被视为纯 JavaScript,而不是字符串。
JSX 在编译时并不会检查expression solts是否有效!它只是将内容转发到纯 JS 输出,并不会做任何额外的事情。
import React from "react"
import { render } from “react-dom”
const shopping_list = ["apple", "banana", "carrot"];
const element = (
<div>
Purchase: {shopping_list.length}
</div>
)
const compliedElement = React.createElement(
"div",
{},
"Purchase: "
shoppingList.length
)
const root = document.querySelector("#root");
// render(element, root)
render(compliedElement, root);
你会发现程序输出没有任何变化!
所以如果你在expression slot中做一些条件判断的语句,它会发生错误,但这错误并不是jsx不允许,而是javascript不允许。
import React from "react"
import { render } from “react-dom”
const shopping_list = ["apple", "banana", "carrot"];
const element = (
<div>
Purchase: {if ( shoppingList.length < 5) "Almost done!"}
</div>
)
const compliedElement = React.createElement(
"div",
{},
"Purchase: "
if ( shoppingList.length < 5) "Almost done!"
)
const root = document.querySelector("#root");
// render(element, root)
render(compliedElement, root);
很显然,我们不能将这种条件判断语句这样放在函数的参数中。
HTML与JSX的区别
JSX 看起来像 HTML,但有一些根本的区别
关键字的保留
JavaScript 有几十个“关键字”。关键字是具有内置功能的关键字。因为它们已经做了一些事情,所以我们不能在 JSX 中使用它们。
但有一个问题,就是 HTML 属性有时与 JavaScript 关键字重叠。
const element = (
<div>
<label for="name">
Name:
</label>
<input
id="name"
class="fun-input"
/>
</div>
);
如果我们将其编译成 JavaScript,我们会发现我们使用了两个保留字:for,class。
为了解决这个冲突,React 对这两个术语使用了细微的变化:
-
for
改为htmlFor
class
更改为className
const element = (
<div>
<label htmlFor="name">
Name:
</label>
<input
id="name"
className="fun-input"
/>
</div>
);
区分大小写的属性
在 JSX 中,我们的属性需要是“camelCase” ,这是有效的html:
<video
src="/videos/cat-skateboarding.mp4"
autoplay="true"
>
在 JSX 中,我们需要将“autoplay”中的“p”大写,因为“auto”和“play”是不同的词:
const element = (
<video
src="/videos/cat-skateboarding.mp4"
autoPlay={true}
// ^ Capital “P”
/>
);
style的应用
html中我们可以这么写:
<article style="filter: var(--shadow-elevation-high)"></article>
但在jsx中肯定是不行的,需要如下所示:
<article style={ { filter: "var(--shadow-elevation-high)" } }></article>
我们需要往expression slots中传入一个对象。
还有jsx标签必须闭合、必须小写等等。
空格陷阱
import { createRoot } from 'react-dom/client';
const daysUntilSantaReturns = 123;
const element = (
<div>
<strong>
Days until Santa returns:
</strong>
{daysUntilSantaReturns}
</div>
);
const container = document.querySelector('#root');
const root = createRoot(container);
root.render(element);
如上代码显示的会是:returns:123,而不是returns: 123,粗体文本和数字之间没有空格。
为什么会这样呢?
让我们考虑一下这个 JSX 如何编译为 JavaScript
const element = React.createElement(
'div',
{},
React.createElement(
'strong',
{},
'Days until Santa returns:'
),
daysUntilSantaReturns
);
请记住, JSX 不会编译为 HTML,它会编译为 JavaScript。当执行该 JavaScript 时,它只会创建并附加两个 HTML 节点:
那么我们该如何解决呢?最常见的解决方案是在大括号中添加单个空白字符:
<div>
<strong>Days until Santa returns:</strong>
{' '}
{daysUntilSantaReturns}
</div>
然而在 HTML 中,每个空白字符(以及换行符!)都会产生一个可见的空格。例如,假设我们有 3 个并排的图像(请参见下面的代码游乐场)。默认情况下,HTML 将在它们之间使用单个空白字符来呈现它们。