[React 基础系列] 什么是 JSX,以及如何使用 JSX
Posted GoldenaArcher
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[React 基础系列] 什么是 JSX,以及如何使用 JSX相关的知识,希望对你有一定的参考价值。
[React 基础系列] 什么是 JSX,以及如何使用 JSX
React 是由 facebook 开发、开源并维护的一个库,而 React 的意义是在于使用 javascript 去实现用户交互——a JavaScript library for building user interfaces。
所以,本质上来说,React 是一个 库,而且它的作用是使用 JavaScript 去实现 用户交互。
它的核心理念是用 JavaScript 去实现 html、CSS 和 JavaScript,通过组件化的概念实现单独的功能。
什么是 JSX
关于 JSX 的介绍,官网也有:Introducing JSX,并且也有中文翻译,有需求也可以到官网上看一下。尽管感觉像是机翻的
JSX 是 React 团队所提供的一个 JavaScript 语法扩展(以前也叫做语法糖)。它的写法和 HTML 有些相似,不过要注意,JSX 不是 HTML,不通过 babel 编译,直接使用 JSX,只会出现大量的语法错误。JSX 的最简单写法如下:
const element = <h1>Hello World</h1>;
ReactDOM.render(element, document.getElementById('root'));
渲染效果如下:
当然,我直接用 npx create-react-app app
创建了一个新的项目,这是重写了项目中的源码,才会有这样的效果——未经过 babel 编译的源码是无法直接在浏览器中运行的。
除此之外,JSX 也可以内嵌其他的变量,具体用法如下:
const name = 'John Wick';
const element = <h1>Hello, {name}</h1>;
ReactDOM.render(element, document.getElementById('root'));
效果如下:
使用 JSX 语法糖并不是必须的,也可以使用 JavaScript 直接进行编写,只不过这样的实现性和可读性都会低很多。下面是一组对比,原生的 JavaScript 是通过 babel 转译所获得:
-
只有 1 个 h1 标签
使用 JSX 的实现如下:
const element = <h1>Hello World</h1>; ReactDOM.render(element, document.getElementById('root'));
使用原生 JavaScript 的实现如下:
var element = /*#__PURE__*/ React.createElement('h1', null, 'Hello World'); ReactDOM.render(element, document.getElementById('root'));
-
1 个变量 + 1 个 h1 标签
使用 JSX 的实现如下:
const name = 'John Wick'; const element = <h1>Hello, {name}</h1>; ReactDOM.render(element, document.getElementById('root'));
使用原生 JavaScript 的实现如下:
var name = 'John Wick'; var element = /*#__PURE__*/ React.createElement('h1', null, 'Hello, ', name); ReactDOM.render(element, document.getElementById('root'));
-
再嵌套一个组件
使用 JSX 的实现如下:
const username = 'John Wick'; const element = ( <h1> Hello, <span>{username}</span> </h1> ); ReactDOM.render(element, document.getElementById('root'));
使用原生 JavaScript 的实现如下:
var username = 'John Wick'; var element = /*#__PURE__*/ React.createElement( 'h1', null, 'Hello, ', /*#__PURE__*/ React.createElement('span', null, username) ); ReactDOM.render(element, document.getElementById('root'));
可以看到,使用 JSX 编写的代码逻辑更加清晰,代码量也更少。再加上现在前端项目在进入生产环境之前总是要通过编译的,这也是为什么推荐使用 JSX 进行开发的原因。
下面就来看看 JSX 的具体用法。
表达式
JSX 本身的功能还挺强大的,从上面的例子中可以看到,JSX 可以嵌入一个表达式,同时,JSX 也可以作为作为一个表达式。
JSX 嵌入表达式
这就是案例 2 和案例 3 中的例子:
const name = 'John Wick';
const element = <h1>Hello, {name}</h1>;
可以看到,表达式/expression name
被嵌入到了 JSX 中。也因为这个特性,JSX 还能够嵌入他一些特殊的表达式。
在 JSX 使用函数
很多情况下,JSX 可以在 {}
体内进行简单的函数调用,例如说对数组的操作:
const fruits = [
{
id: 1,
name: 'apple',
price: 4,
},
{
id: 2,
name: 'banana',
price: 2,
},
];
const getFruitList = (fruits) => {
return (
<ul>
{fruits.map((fruit) => (
<li key={id}>
<p>name: {fruit.name}</p>
<p>price: {fruit.price}</p>
</li>
))}
</ul>
);
};
const fruitList = getFruitList(fruits);
渲染后的结果如下:
JSX 作为表达式
同样,JSX 也可以作为一个值去被赋给对象,如:
const component = <ExampleComponent />;
ReactDOM.render(component, document.getElementById('root'));
这是一种比较常见的用法。
以三元表达返回 JSX
这也是一个比较常见的写法,有的时候会根据条件去判断是否返回一个组件的时候,就可以这么做:
const child = condition ? <ExampleComponent /> : null;
return (
<SomeComponent>
<OtherComponent />
{child}
</SomeComponent>
);
一般来说这种组件会被嵌入到其他的组件内去进行渲染。
JSX 与对象
JSX 的语法如此动态的原因,本质上是因为在经过编译之后,JSX 会被 babel 转化为一个对象。
如案例 1 所示:
const element = <h1>Hello World</h1>;
var element = /*#__PURE__*/ React.createElement('h1', null, 'Hello World');
两段代码本质上是一样的,createElement()
具体的内容不会过对赘述,但是它所做的就是返回一个对象。官网上有一个 createElement()
返回结果的简化版,大概就能知道它是接收一些参数,然后以对象的形式进行保存结果:
// Note: this structure is simplified
const element = {
type: 'h1',
// 对象的属性
props: {
// 类名,后面会解释
className: 'greeting',
// 子属性
children: 'Hello, world!',
},
};
属性
JSX 的属性分为两种,一种是原生的 HTML 就有的属性——注意为了防止关键字冲突,有些大小写会发生变化,另外一种就是自定义的属性,可以通过 props
在子组件中获取,完成父子组件的通信。
鉴于这里还没有完整的讲过组件的特性,所以会以基本的 HTML 属性为例:
const username = 'John Wick';
const element = (
<h1 className="h1-heading">
Hello, <span className="username">{username}</span> <br />
<img
src="https://img-blog.csdnimg.cn/20210706102601893.png"
style={{ width: '350px' }}
/>
</h1>
);
ReactDOM.render(element, document.getElementById('root'));
编译后的效果如下:
值得注意的一点就是,为了防止关键字冲突,HTML 中定义类名使用的是 class 关键字,在 JSX 中使用的是 className。通过这一点也可以看出来,在编写 React 代码过程中还是建议使用传统 JavaScript 的驼峰命名法。
另:onClick,onChange 这些事件也可以作为属性传到 JSX 代码中去,这点会在之后讲组件的部分进行详解,这里只要知道就好。
另 2:样式,style 也可以作为属性,这种情工况下写出来的样式就是行内样式。
子组件
JSX 的嵌套就已经形成了父子组件,依旧以上面的代码为例:
const element = (
<h1 className="h1-heading">
Hello, <span className="username">{username}</span> <br />
<img
src="https://img-blog.csdnimg.cn/20210706102601893.png"
style={{ width: '350px' }}
/>
</h1>
);
在这个例子中,h1 就是父组件,而 img 和 span 就是子组件。注意,如果标签中没有额外的子组件,如 img 组件,那么就可以使用自闭合标签。
注入攻击
这也是年初的时候再次浏览官方文档的时候才发现的一个特性,原来 JSX 原生可以避免 XSS(cross-site-scripting) 攻击。XSS 指的是将恶意指令注入到 HTML 中,使得用户加载并且执行攻击的一种恶意程序。以下面的代码为例,如果这段代码作为用户输入的信息,而前端又没有进行任何的预防,那么该网站就会被攻击:
const userinput =
"<a href='https://www.baibu.com' onClick={alert('attacked')}>超链接</a>";
如下面这里的 HTML 简单的实现了一个 input,然后会有另外一个节点渲染用户信息:
<input type="text" />
<div class="inputValue"></div>
<script>
const input = document.querySelector('input');
const inputValue = document.querySelector('.inputValue');
input.addEventListener('change', () => {
inputValue.innerHTML = input.value;
});
</script>
当上面这段超链接代码被放入了输入框中后,页面就成了这样:
用户一旦点击 超链接
,就会触发攻击:
JSX 会对代码进行转译,同样的代码放入 JSX 中,显示渲染的依旧是原本的代码:
const userinput =
"<a href='https://www.baidu.com' onClick={alert('attacked')}>超链接</a>";
const element = <input type="text" value={userinput} />;
const inputValue = <div>{userinput}</div>;
ReactDOM.render(
<Fragment>
{element}
{inputValue}
</Fragment>,
document.getElementById('root')
);
显示效果:
这是因为 JSX 会将所有输入的信息全都转译成字符串,再渲染到页面上,这就能够有效的避免 XSS 攻击。
以上是关于[React 基础系列] 什么是 JSX,以及如何使用 JSX的主要内容,如果未能解决你的问题,请参考以下文章