乐趣区

关于前端:React-系列二核心JSX语法

快来退出咱们吧!

“ 小和山的菜鸟们 ”,为前端开发者提供技术相干资讯以及系列根底文章。为更好的用户体验,请您移至咱们官网小和山的菜鸟们 (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>
    )
  }
}
退出移动版