共计 7462 个字符,预计需要花费 19 分钟才能阅读完成。
快来退出咱们吧!
“ 小和山的菜鸟们 ”,为前端开发者提供技术相干资讯以及系列根底文章。为更好的用户体验,请您移至咱们官网小和山的菜鸟们 (https://xhs-rookies.com/) 进行学习,及时获取最新文章。
“Code tailor”,如果您对咱们文章感兴趣、或是想提一些倡议,微信关注 “小和山的菜鸟们” 公众号,与咱们取的分割,您也能够在微信上观看咱们的文章。每一个倡议或是同意都是对咱们极大的激励!
前言
这节咱们将教你一个乏味的标签语法,他既不是字符串也不是 HTML
,他被称为 JSX
,是一个 JavaScript
的语法扩大,咱们倡议在 React
中配合应用 JSX
,JSX
能够很好地形容 UI
应该呈现出它应有交互的实质模式。
本文会向你介绍以下内容:
- 意识
JSX
的语法 - 在
JSX
中嵌入表达式 - 事件监听
- 条件渲染
- 列表渲染
JSX
原理解析- 案例练习
意识 JSX 的语法
JSX 是什么?
咱们先来看一段代码:
const element = <h1>Hello, XHS-Rookies!</h1>
这段 element
变量的申明右侧赋值的标签语法是什么呢?
这个乏味的标签语法既不是字符串也不是 HTML
。
它被称为 JSX
,是一个 JavaScript
的语法扩大。咱们倡议在 React
中配合应用 JSX
,JSX
能够很好地形容 UI 应该呈现出它应有交互的实质模式。JSX
可能会使人联想到模版语言,但它具备 JavaScript
的全副性能。
留神: 对于
JSX
来说,尽管是一种JavaScript
语法扩大,然而你能发现其无奈间接应用在HTML
中,须要借助babel
的转换,转换后会主动帮我解析成想要的款式。
为什么应用 JSX?
React
认为渲染逻辑实质上与其余 UI
逻辑外在耦合,比方,在 UI
中须要绑定处理事件、在某些时刻状态发生变化时须要告诉到 UI
,以及须要在 UI
中展现筹备好的数据。
React
并没有采纳将标记与逻辑进行拆散到不同文件这种人为地拆散形式,而是通过将二者独特寄存在称之为“组件”的涣散耦合单元之中,来实现关注点拆散。
React
不强制要求应用 JSX
,然而大多数人发现,在 JavaScript
代码中将 JSX
和 UI
放在一起时,会在视觉上有辅助作用。它还能够使 React
显示更多有用的谬误和正告音讯。
JSX 的书写标准:
JSX
的顶层 只能有一个根元素,所以咱们很多时候会在外层包裹一个div
原生;- 为了不便浏览,咱们通常在
jsx
的外层包裹一个小括号(),这样能够不便浏览,并且jsx
能够进行换行书写; JSX
中的标签能够是单标签,也能够是双标签;
留神: 如果是单标签,必须以
/>
结尾;
在 JSX 中嵌入表达式
如果咱们 jsx
中的内容是动静的,咱们能够通过表达式来获取:
书写规定:{表达式},大括号内能够是变量、字符串、数组、函数调用等任意 js
表达式;
JSX 中的正文
这是嵌入到 JavaScript
中的一种语法,所以在编写正文时,须要通过 JSX
的语法来编写:
<div>
{/* 我是一段正文 */}
<h2>Hello World</h2>
</div>
JSX 嵌入变量
状况一: 当变量是 Number
、String
、Array
类型时,能够间接显示
状况二: 当变量是 null
、undefined
、Boolean
类型时,内容为空;
- 如果想要显示
null
、undefined
、Boolean
,那么须要转成字符串;转换的形式有很多,比方toString
办法、和空字符串拼接,String
(变量)等形式;
状况三: 对象类型不能作为子元素(not valid as a React child
)
class App extends React.Component {render() {
let data = {
name: 'xhs-rookies',
age: 18,
skills: ['JavaScript', 'React', 'Webpack'],
test1: null,
test2: undefined,
flag: false,
friend: {
name: 'xhs-zymxxxs',
age: 29,
},
}
return (
<div>
<div>
{/* 我是一段正文 */}
<h2>Hello React</h2>
</div>
<div>
{/* 1. 能够间接显示 */}
<h2>{data.name}</h2>
<h2>{data.age}</h2>
<h2>{data.skills}</h2>
{/* 2. 不显示 */}
<h2>{data.test1}</h2>
<h2>{data.test1 + ''}</h2>
<h2>{data.test2}</h2>
<h2>{data.test2 + ''}</h2>
<h2>{data.flag}</h2>
<h2>{data.flag + ''}</h2>
{/* 3. 不显示 */}
<h2>123{data.friend}</h2>
</div>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
为什么 null、undefined、Boolean 在 JSX 中要显示为空内容呢? 起因是在开发中会进行很多的判断;
- 在判断后果为 false 时,不显示一个内容;
- 在判断后果为 true 时,显示一个内容;
JSX 嵌入表达式
在 JSX 语法中,你能够在大括号内搁置任何无效的 JavaScript 表达式。例如,2 + 2,user.firstName 或 formatName(user) 都是无效的 JavaScript 表达式。
在上面的示例中,咱们将调用 JavaScript 函数 formatName(user) 的后果,并将后果嵌入到 <h1>
元素中。
function formatName(user) {return user.firstName + ' ' + user.lastName}
const user = {
firstName: 'xhs',
lastName: 'rookies',
}
const element = <h1>Hello, {formatName(user)}!</h1>
ReactDOM.render(element, document.getElementById('root'))
JSX 绑定属性
你能够通过应用引号,来将属性值指定为字符串字面量:
const element = <div className="active"></div>
也能够应用大括号,来在属性值中插入一个 JavaScript
表达式:
const element = <img src={user.avatarUrl}></img>
在属性中嵌入 JavaScript
表达式时,不要在大括号里面加上引号。你应该仅应用引号(对于字符串值)或大括号(对于表达式)中的一个,对于同一属性不能同时应用这两种符号。
事件监听
和原生绑定区别
如果原生 DOM
原生有一个监听事件,咱们能够如何操作呢?
- 形式一:获取
DOM
原生,增加监听事件; - 形式二:在
HTML
原生中,间接绑定onclick
;
咱们这里演练一下形式二:
btnClick()
这样写的起因是onclick
绑定的前面是跟上JavaScript
代码;
<button onclick="btnClick()"> 点我一下 </button>
<script>
function btnClick() {console.log('按钮产生了点击')
}
</script>
在 React
中是如何操作呢?
咱们来实现一下 React
中的事件监听,这里次要有两点不同
React
事件的命名采纳小驼峰式(camelCase
),而不是纯小写;- 咱们须要通过 {} 传入一个事件处理函数,这个函数会在事件产生时被执行;
class App extends React.Component {render() {
return (
<div>
<button onClick={this.btnClick}> 点我一下 </button>
</div>
)
}
btnClick() {console.log('React 按钮点击了一下')
}
}
事件的 this 绑定
你必须审慎看待 JSX
回调函数中的 this
,在 JavaScript
中,class
的办法默认不会绑定 this
。如果你遗记绑定 this.handleClick
并把它传入了 onClick
,当你调用这个函数的时候 this
的值为 undefined
。
class LoggingButton extends React.Component {handleClick() {console.log('this is:', this)
}
render() {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。return <button onClick={() => this.handleClick()}>Click me</button>
}
}
如果你想理解 bind
和箭头函数对 this
应用的区别,能够抉择查看 bind 和箭头函数的区别
事件参数传递
在执行事件函数时,有可能咱们须要获取一些参数信息:比方 event
对象、其余参数
状况一:获取 event
对象
- 很多时候咱们须要拿到
event
对象来做一些事件(比方阻止默认行为) - 如果咱们用不到
this
,那么间接传入函数就能够获取到event
对象;
class App extends React.Component {btnClick(e) {e.preventDefault()
console.log(e)
}
render() {
return (
<div>
<a href="https://xhs-rookies.com/" onClick={this.btnClick}>
点我一下
</a>
</div>
)
}
}
状况二:获取更多参数
- 有更多参数时,咱们最好的形式就是传入一个箭头函数,被动执行的事件函数,并且传入相干的其余参数;
class App extends React.Component {render() {
let data = {names: ['衣服', '鞋子', '裤子'],
}
return (
<div>
<a href="https://xhs-rookies.com/" onClick={this.aClick}>
点我一下
</a>
{data.names.map((item, index) => {
return (<a href="#" onClick={(e) => this.aClick(e, item, index)}>
这里是{item}
</a>
)
})}
</div>
)
}
aClick(e, item, index) {e.preventDefault()
console.log(item, index)
console.log(e)
}
}
条件渲染
某些状况下,界面的内容会依据不同的状况显示不同的内容,或者决定是否渲染某局部内容:
在 React
中,所有的条件判断都和一般的 JavaScript
代码统一;
常见的条件渲染的形式有哪些呢?
条件判断语句
一种形式是当逻辑较多时,通过条件判断:
class App extends React.Component {render() {
let data = {isLogin: true,}
let titleJsx = null
if (data.isLogin) {titleJsx = <h2> 欢送回来~</h2>} else {titleJsx = <h2> 请先登录~</h2>}
return <div>{titleJsx}</div>
}
}
当然,咱们也能够将其封装到一个独立的函数中:
class App extends React.Component {
this.data = {isLogin: true}
render() {
return (
<div>
{this.getTitleJsx()}
</div>
)
}
getTitleJsx() {
let titleJsx = null;
if (this.data.isLogin) {titleJsx = <h2> 欢送回来~</h2>} else {titleJsx = <h2> 请先登录~</h2>}
return titleJsx;
}
}
三元运算符
另外一种实现条件渲染的办法就是三元运算符:condition ? true : false;
三元运算符实用于没有太多逻辑的代码:只是依据不同的条件间接返回不同的后果
class App extends React.Component {constructor(props) {super(props)
this.state = {isLogin: true,}
}
render() {
return (
<div>
<h2>{this.state.isLogin ? '欢送回来~' : '请先登录~'}</h2>
<button onClick={(e) => this.loginBtnClick()}>
{this.state.isLogin ? '退出' : '登录'}
</button>
</div>
)
}
loginBtnClick() {
this.setState({isLogin: !this.state.isLogin,})
}
}
与运算符 &&
在某些状况下,咱们会遇到这样的场景:
- 如果条件成立,渲染某一个组件;
- 如果条件不成立,什么内容也不渲染;
如果咱们应用三元运算符,是如何做呢?
{this.state.isLogin ? <h2>{this.state.username}</h2> : null
}
其实咱们能够通过 逻辑与 &&
来简化操作:
{this.state.isLogin && <h2>{this.state.username}</h2>
}
列表渲染
列表渲染
在开发中咱们会从服务器申请到大量的数据,数据会以数组的模式存储。
咱们须要通过 JavaScript
代码的形式组织数据,转成 JSX
。
咱们来演练一个案例:
class App extends React.Component {constructor(props) {super(props)
this.state = {skills: ['HTML', 'CSS', 'JavaScript', 'React', 'Node'],
}
}
render() {
return (
<div>
<h2> 前端技能 </h2>
<ul>
{this.state.skills.map((item) => {return <li>{item}</li>
})}
</ul>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
数组解决
很多时候咱们在展现一个数组中的数据之前,须要先对它进行一些解决:
- 比方过滤掉一些内容:
filter
函数 - 比方截取数组中的一部分内容:
slice
函数
比方我以后有一个数组中寄存了一系列的数字:[10, 30, 120, 453, 55, 78, 111, 222]
案例需要:从给定数组中获取所有大于等于 50 的数字,并且展现前 3 个数字
class App extends React.Component {constructor(props) {super(props)
this.state = {numbers: [10, 30, 120, 453, 55, 78, 111, 222],
}
}
render() {
return (
<div>
<h2> 数字列表 </h2>
<ul>
{this.state.numbers
.filter((item) => item >= 50)
.slice(0, 3)
.map((item) => {return <li>{item}</li>
})}
</ul>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
列表的 key
咱们会发现在后面的代码中只有展现列表都会报一个正告:
列表展现正告
这个正告是通知咱们须要在列表展现的 jsx
中增加一个 key
。
至于为什么须要 key
,这里波及到react
组件渲染的规定,在特地长列表的时候,或是说 DOM
节点的子元素发送扭转,像是在子元素列表尾部新增元素的时候,只是须要将新增的内容搁置于尾部即可,这没有什么问题。
然而如果须要在列表头部新增元素,那么开销会十分大。为了解决这相似的问题,React
引入了,应用 key 进行优化后,树的转换效率会晋升。
具体对于 key 的内容请见:
列表 & Key – React (reactjs.org)
深刻了解为什么 key 是必须的
JSX 原理解析
JSX 转换实质
实际上,jsx
仅仅只是 React.createElement(component, props, ...children)
函数的语法糖。所有的 jsx 最终都会被转换成 React.createElement
的函数调用。如果你想深刻理解 JSX
的实现原理,请详见深刻 JSX
案例练习
列表展现
实在开发中,咱们的数据通常会从服务器获取,比拟常见的是获取一个列表数据,保留到一个数组中进行展现
- 比方当初有一个代办事项列表,咱们如何通过 React 进行展现呢?
咱们还是通过一个组件来实现:
class App extends React.Component {constructor(props) {super(props)
this.state = {things: ['写文章', '散会', '上课', '读书'],
}
}
render() {
return (
<div>
<h2> 代办事项列表 </h2>
<ul>
{this.state.things.map((item, index) => {return <li>{index + 1 + '.' + item}</li>
})}
</ul>
</div>
)
}
}
点赞性能案例
代办事项列表的案例中并没有交互,咱们再来实现一个点赞性能的案例:
class App extends React.PureComponent {constructor() {super()
this.state = {
isLike: false,
likeNum: 233,
}
}
likeOrUnlike() {if (this.state.isLike) {
this.setState({
isLike: false,
likeNum: this.state.likeNum - 1,
})
} else {
this.setState({
isLike: true,
likeNum: this.state.likeNum + 1,
})
}
}
render() {console.log('render')
return (
<div>
<p> 点赞人数:{this.state.likeNum}</p>
<button onClick={(e) => this.likeOrUnlike()}>
{this.state.isLike ? '勾销点赞' : '点赞'}
</button>
</div>
)
}
}