快来退出咱们吧!

"小和山的菜鸟们",为前端开发者提供技术相干资讯以及系列根底文章。为更好的用户体验,请您移至咱们官网小和山的菜鸟们 ( https://xhs-rookies.com/ ) 进行学习,及时获取最新文章。

"Code tailor" ,如果您对咱们文章感兴趣、或是想提一些倡议,微信关注 “小和山的菜鸟们” 公众号,与咱们取的分割,您也能够在微信上观看咱们的文章。每一个倡议或是同意都是对咱们极大的激励!

前言

这节咱们将教你一个乏味的标签语法,他既不是字符串也不是 HTML,他被称为 JSX,是一个 JavaScript 的语法扩大,咱们倡议在 React 中配合应用 JSXJSX 能够很好地形容 UI 应该呈现出它应有交互的实质模式。

本文会向你介绍以下内容:

  • 意识 JSX 的语法
  • JSX 中嵌入表达式
  • 事件监听
  • 条件渲染
  • 列表渲染
  • JSX 原理解析
  • 案例练习

意识 JSX 的语法

JSX 是什么?

咱们先来看一段代码:

const element = <h1>Hello, XHS-Rookies!</h1>

这段 element 变量的申明右侧赋值的标签语法是什么呢?

这个乏味的标签语法既不是字符串也不是 HTML

它被称为 JSX,是一个 JavaScript 的语法扩大。咱们倡议在 React 中配合应用 JSXJSX 能够很好地形容 UI 应该呈现出它应有交互的实质模式。JSX 可能会使人联想到模版语言,但它具备 JavaScript 的全副性能。

留神: 对于JSX来说,尽管是一种JavaScript语法扩大,然而你能发现其无奈间接应用在HTML中,须要借助babel的转换,转换后会主动帮我解析成想要的款式。

为什么应用 JSX?

React 认为渲染逻辑实质上与其余 UI 逻辑外在耦合,比方,在 UI 中须要绑定处理事件、在某些时刻状态发生变化时须要告诉到 UI,以及须要在 UI 中展现筹备好的数据。

React 并没有采纳将标记与逻辑进行拆散到不同文件这种人为地拆散形式,而是通过将二者独特寄存在称之为“组件”的涣散耦合单元之中,来实现关注点拆散。

React 不强制要求应用 JSX,然而大多数人发现,在 JavaScript 代码中将 JSXUI 放在一起时,会在视觉上有辅助作用。它还能够使 React 显示更多有用的谬误和正告音讯。

JSX 的书写标准:

  • JSX 的顶层只能有一个根元素,所以咱们很多时候会在外层包裹一个 div 原生;
  • 为了不便浏览,咱们通常在 jsx 的外层包裹一个小括号(),这样能够不便浏览,并且 jsx 能够进行换行书写;
  • JSX 中的标签能够是单标签,也能够是双标签;
留神: 如果是单标签,必须以/>结尾;

在 JSX 中嵌入表达式

如果咱们 jsx 中的内容是动静的,咱们能够通过表达式来获取:

书写规定:{表达式},大括号内能够是变量、字符串、数组、函数调用等任意 js 表达式;

JSX 中的正文

这是嵌入到 JavaScript 中的一种语法,所以在编写正文时,须要通过 JSX 的语法来编写:

<div>  {/* 我是一段正文 */}  <h2>Hello World</h2></div>

JSX 嵌入变量

状况一: 当变量是 NumberStringArray 类型时,能够间接显示

状况二: 当变量是 nullundefinedBoolean 类型时,内容为空;

  • 如果想要显示 nullundefinedBoolean,那么须要转成字符串;转换的形式有很多,比方 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>    )  }}