JSX基础语法

文章目录

  • 认识JSX语法
    • JSX是什么
    • 为什么Rect选择了JSX
    • JSX书写规范
    • JSX注释编写
  • JSX的基本使用
  • JSX的事件绑定
    • this绑定问题
    • 参数传递问题
  • JSX的条件渲染
    • 常见的条件渲染方式
  • JSX的列表渲染
  • JSX的原理和本质
    • JSX的本质
    • 虚拟DOM的创建过程
  • 案例练习


认识JSX语法

// 1. 定义根组件
const element = <div>Hello World</div>// 2. 渲染根组件
const root = ReactDOM.createRoot(document.querySelector("#root"))
root.render(element)

上述代码中element变量的声明右侧赋值的标签语法其实就是一段JSX的语法。

  • 它不是一段字符串(因为没有使用引号包裹)
  • 它看起来是一段HTML元素,但是我们能在js中直接给一个变量赋值HTML吗?其实是不可以的,如果我们将type = "text/babel" 去除掉,那么就会出现语法错误。

JSX是什么

JSX是一种JavaScript的语法扩展,也在很多地方称之为JavaScript XML,因为看起来就是一段XML语法,它用于描述我们的UI界面,并且其完成可以和JavaScript融合在一起使用,它不同于Vue中的模块语法,不需要专门学习模块语法中的一些指令(比如v-if、v-for、v-bind等)

为什么Rect选择了JSX

React认为渲染逻辑本质上与其他UI逻辑存在内在耦合。比如UI需要绑定事件(button、a原生等等)、比如UI中需要展示数据的状态、比如在某些状态发生改变时,又需要改变UI,它们之间是密不可分的,所以React没有将标记分离到不同的文件中,而是将它们组合到了一起,这个地方就是组件。

image-20231024111707288

JSX书写规范

  • JSX的顶层只能有一个根元素,所以我们很多时候会在外层包裹一个div元素(或者Fragment)
  • 为了方便阅读,我们通常在jsx的外层包裹一个小括号(),这样可以方便阅读,并且jsx可以进行换行书写
  • JSX中的标签可以是单标签,也可以是双标签(如果是单标签,必须以/>结尾)
return (<div><div><h2>{message}</h2></div><div>哈哈哈</div></div>
)

JSX注释编写

return (<div>{/* JSX的注释写法*/}<h2>{message}</h2></div>
)

JSX的基本使用

  1. JSX嵌入变量作为子元素

    • 情况一:当变量是Number、String、Array类型时,可以直接显示
    • 情况二:当变量是null、undefined、Boolean类型时,内容为空
      • 如果希望可以显示null、undefined、Boolean,那么需要转成字符串
      • 转换的方式有很多,比如toString方法、和空字符串拼接、String等方式
    • 情况三:Object对象类型不能作为子元素
  2. JSX嵌入表达式

    • 运算表达式
    • 三元运算符
    • 执行一个函数
  3. JSX绑定属性

    • 比如元素都会有title属性
    • 比如img元素会有src属性
    • 比如a元素会有href属性
    • 比如元素可能需要绑定class
    • 比如元素使用内联样式style

JSX的事件绑定

如果原生DOM有一个监听事件,我们可以如何操作?

  • 方式一:获取DOM元素,添加监听事件
  • 方式二:在HTML原生中,直接绑定onclick

在React中是如何操作呢?

  • React事件的命名采用小驼峰(cameClass),而不是纯小写
  • 我们需要通过{}传入一个事件处理函数,这个函数会在事件发生时被执行
<body><div id="root"></div><script type="text/babel">// 类组件class App extends React.Component {// 组件数据constructor() {super()this.state = {message: "Hello World"}}// 组件方法btnClick() {// 内部完成了两件事:// 1. 将state中的message值修改掉// 2. 自动重新执行render函数this.setState({message: "Hello React"})}// 渲染内容render() {// 简单数据// return <h2>Hello World</h2>// 复杂数据return (<div><h2>{this.state.message}</h2><button onClick={this.btnClick.bind(this)}>修改文本</button></div>)}// 为什么这里要bind一下? 因为类中的方法中的this默认指向undefined, 所以要将render函数中的this给方法}// 将组件渲染到界面上const container = document.getElementById('root');const root = ReactDOM.createRoot(container);root.render(<App />);</script>
</body>

这种数据的数据是定义在当前对象的state中的,我们可以通过构造函数中的this.state={定义的数据},然后当我们数据发生变化时,我们可以调用this.setState来更新数据,并且通知React进行update操作,在进行update操作时,会重新调用render函数,并且使用最新的数据来渲染界面。

this绑定问题

上述代码还存在this绑定问题

在事件执行后,我们可能需要获取当前类的对象中相关的属性,这个时候需要用到this。

在类中直接定义一个函数,并且将这个函数绑定到元素的onClick事件上,当前这个函数的this指向是谁呢?

默认情况下是undefined,因为在正常的DOM操作中,监听点击,监听函数中的this其实是节点对象(比如说button对象),但是因为React并不是直接渲染成真实DOM,我们所编写的button只是一个语法糖,它的本质React的Element对象,那么在这里发生监听的时候,react在执行函数时并没有绑定this,默认情况下就是一个undefined。

我们在绑定的函数中,可能想要使用当前对象,比如执行this.setState函数,就必须拿到当前对象的this,我们就需要在传入函数时,给这个函数直接绑定this:

  • 方案一:bind给btnClick显式绑定this
// 写法一
<button onClick={this.btnClick.bind(this)}>修改文本</button>// 写法二
constructor() {super()this.state = {message: "Hello World"}this.btnClick = this.btnClick.bind(this)
}
  • 方案二:使用ES6 class fields 语法
  • 方案三:事件监听时传入箭头函数(推荐)
<body><div id="root"></div><script type="text/babel">/*this的四种绑定规则:1. 默认绑定 独立执行 2. 隐式绑定 作为对象中的方法执行3. 显式绑定 call apply bind4. new绑定*/class App extends React.Component {constructor() {super()this.state = {counter: 100}}btn1Click() {console.log("btn1Click")this.setState({ counter: this.state.counter + 1 })}// 所有实例都会有btn2Click这个字段,将一个箭头函数赋值给btn2Click,而箭头函数没有this,就会去上层作用域中查找,找到的是当前类的作用域的this,而this正好指向当前实例btn2Click = () => {console.log("btn2Click")this.setState({ counter: this.state.counter + 1 })}btn3Click = () => {console.log("btn3Click")this.setState({ counter: this.state.counter + 1 })}render() {return (<div><h2>当前计数:{this.state.counter}</h2>{/*1. this绑定方式一:bind绑定*/}<button onClick={this.btn1Click.bind(this)}>按钮1</button>{/*2. this绑定方式二:ES6 class fields*/}<button onClick={this.btn2Click}>按钮2</button>{/*3. this绑定方式三:直接传入一个箭头函数(重要)*/}<button onClick={() => this.btn3Click()}>按钮3</button>{/*怎么做的?形成一个隐式绑定,this是当前实例,btn3Click作为当前实例的方法被调用*/}</div>)}}const container = document.getElementById('root');const root = ReactDOM.createRoot(container);root.render(<App />);</script>
</body>

参数传递问题

  • 情况一:获取event对象
    • 很多时候我们需要拿到event对象来做一些事情(比如阻止默认行为)
    • 那么默认情况下,event对象有被直接传入,函数就可以获取到event对象
  • 情况二:获取更多参数
    • 有更多参数时,最好的方式就是传入一个箭头函数,主动执行的事件函数,并且传入相关的其他参数
<body><div id="root"></div><script type="text/babel">class App extends React.Component {constructor() {super()this.state = {counter: 100}}btn1Click(event) {console.log("btn1Click", event)}btn2Click(event, name, age) {console.log("btn2Click", event, name, age)}render() {return (<div><h2>当前计数:{this.state.counter}</h2>{/*1. event参数的传递 */}<button onClick={this.btn1Click.bind(this)}>按钮1</button><button onClick={(event) => this.btn1Click(event)}>按钮1</button>{/*2. 额外的参数传递*/}<button onClick={this.btn2Click.bind(this,)}>按钮2</button><button onClick={(event) => this.btn1Click(event, "zy", 18)}>按钮2</button></div>)}}const container = document.getElementById('root');const root = ReactDOM.createRoot(container);root.render(<App />);</script>
</body>

JSX的条件渲染

某些情况下,界面的内容会根据不同的情况显示不同的内容,或者决定是否渲染某部分内容:

  • 在vue中,我们会通过指令来控制:比如v-if、v-show
  • 在React中,所有的条件判断都和普通的JavaScript代码一致

常见的条件渲染方式

  • 方式一:条件判断语句,适合逻辑较多的情况
  • 方式二:三元运算符,适合逻辑比较简单
  • 方式三:与运算符&&,适合如果条件成立,渲染某一个组件;如果条件不成立,什么内容也不渲染
<body><div id="root"></div><script type="text/babel">class App extends React.Component {constructor() {super()this.state = {isReady: true}}render() {const { isReady } = this.statelet showElement = nullif (isReady) {showElement = <h2>准备开始比赛吧</h2>} else {showElement = <h2>请提前做好准备!</h2>}return (<div>{/*1. 方式一:根据条件给变量赋值不同的内容*/}<div>{showElement}</div>{/*2. 方式二:三元运算符*/}<div>{isReady ? <button>开始战斗!</button> : <h3>准备</h3>}</div>{/*3. 方式三:&&逻辑与运算*/}{/*场景:当某一个值,有可能为undefined时,使用&&进行条件判断*/}<div>{info && <div>{info.name + " " + info.desc}</div>}</div></div >)}}const container = document.getElementById('root');const root = ReactDOM.createRoot(container);root.render(<App />);</script>
</body>

JSX的列表渲染

真实开发中我们会从服务器请求到大量数据,数据会以列表的形式存储:

  • 比如歌手、歌曲、排行榜列表的数据
  • 比如商品、购物车、评论列表的数据
  • 比如好友消息、动态、联系人列表数据

在React中并没有像Vue模块语法中的v-for指令,而且需要我们通过JavaScript代码的方式组织数据,转成JSX,那到底如何展示列表呢?在React中,展示列表最多的方式就是使用数组的map高阶函数。很多时候我们在展示一个数据之前,需要先对它进行一些处理:比如过滤掉一些内容:filter函数;比如截取数组中的一部分内容:slice函数。

<body><div id="root"></div><script type="text/babel">class App extends React.Component {constructor() {super()this.state = {students: [{ id: 1, name: "zy", score: 99 },{ id: 2, name: "lgc", score: 88 },{ id: 3, name: "mxy", score: 100 },{ id: 4, name: "jack", score: 66 },{ id: 5, name: "kobe", score: 92 },]}}render() {const { students } = this.statereturn (<div><h2>学生列表数据</h2><div className="list">{//  选出成绩大于90分的人students.filter(item => item.score > 90).map(item => {return (<div className="item" key={item.id}><h2>学号:{item.id}</h2><h2>姓名:{item.name}</h2><h2>分数:{item.score}</h2></div>)})}</div></div>)}}const container = document.getElementById('root');const root = ReactDOM.createRoot(container);root.render(<App />);</script>
</body>

JSX的原理和本质

image-20231025111055241

JSX的本质

实际上,jsx仅仅只是React.createElement(component, props, ...children)函数的语法糖,所有的jsx最终都会被转换成React.createElement的函数调用

React.createElement需要传递三个参数:

  1. 参数一:type
    • 当前ReactElement的类型
    • 如果是标签元素,那么就使用字符串表示“div”
    • 如果是组件元素,那么就直接使用组件的名称
  2. 参数二:config
    • 所有jsx中的属性都在config中以对象的属性和值的形式存储
    • 比如传入className作为元素的class
  3. 参数三:children
    • 存放在标签中的内容,以children数组的方式进行存储
    • 如果是多个元素,React内部有对它们进行处理

image-20231025160745269

虚拟DOM的创建过程

我们通过React.createElement最终创建出来一个ReactElement对象,这个ReactElement对象是什么作用呢?React为什么要创建它呢?这是因为React利用ReactElement对象组成了一个JavaScript的对象树,JavaScript的对象树就是虚拟DOM。

如何查看ReactElement的树结构呢?我们可以将之前的就实现返回结果进行打印:

image-20231025161606611

jsx-虚拟DOM-真实DOM

image-20231025161728352

案例练习

要求:

  1. 在界面上以表格的形式,显示一些书籍的数据
  2. 在底部显示书籍的总价格
  3. 点击+或者-可以增加或减少书籍(如果为1,那么不能继续-)
  4. 点击移除按钮,可以将书籍移除(当所有书籍移除完毕时,显示:购物车为空~)

image-20231025163055858

<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>购物车</title><!-- 添加依赖 --><script src="https://unpkg.com/react@18/umd/react.development.js"></script><script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script><!-- babel --><script src="https://unpkg.com/@babel/standalone/babel.min.js"></script><style>table {border-collapse: collapse;text-align: center;}thead {background-color: #f2f2f2;}td,th {padding: 10px 16px;border: 1px solid black;}</style>
</head><body><div id="root"></div><script src="./data.js"></script><script type="text/babel">class App extends React.Component {constructor() {super()this.state = {books: books}}format(price) {return "¥" + Number(price).toFixed(2);}// 方法increment(index) {const newBooks = [...this.state.books]newBooks[index].count += 1this.setState({ books: newBooks })}decrement(index) {const newBooks = [...this.state.books]newBooks[index].count -= 1this.setState({ books: newBooks })}removeItem(index) {const newBooks = [...this.state.books]newBooks.splice(index, 1)this.setState({ books: newBooks })}render() {const { books } = this.state// 计算总价let totalPrice = 0for (let i = 0; i < books.length; i++) {totalPrice += books[i].count * books[i].price}return (<div><table><thead><tr><th>序号</th><th>书籍名称</th><th>出版日期</th><th>价格</th><th>购买数量</th><th>操作</th></tr></thead><tbody >{books.map((item, index) => {return (<tr key={item.id}><td>{item.id}</td><td>{item.name}</td><td>{item.data}</td><td>{this.format(item.price)}</td><td><button disabled={item.count <= 1} onClick={() => this.decrement(index)}>-</button>{item.count}<button onClick={() => this.increment(index)}>+</button></td><td><button onClick={() => this.removeItem(index)}>移除</button></td></tr>)})}</tbody></table><h1>总价格:{this.format(totalPrice)}</h1></div>)}}const container = document.getElementById('root');const root = ReactDOM.createRoot(container);root.render(<App />);</script>
</body></html>
// data.js
const books = [{id: 1,name: '《算法导论》',data: '2006-9',price: 85.0,count: 1,},{id: 2,name: '《UNIX编程艺术》',data: '2006-9',price: 59.0,count: 1,},{id: 3,name: '《编程珠玑》',data: '2006-9',price: 39.0,count: 1,},{id: 4,name: '《代码大全》',data: '2006-9',price: 128.0,count: 1,},
];

container);
root.render();

```
// data.js
const books = [{id: 1,name: '《算法导论》',data: '2006-9',price: 85.0,count: 1,},{id: 2,name: '《UNIX编程艺术》',data: '2006-9',price: 59.0,count: 1,},{id: 3,name: '《编程珠玑》',data: '2006-9',price: 39.0,count: 1,},{id: 4,name: '《代码大全》',data: '2006-9',price: 128.0,count: 1,},
];

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/119176.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RK3568-适配at24c04模块

将at24c04模块连接到开发板i2c2总线上 i2ctool查看i2c2总线上都有哪些设备 UU表示设备地址的从设备被驱动占用,卸载对应的驱动后,UU就会变成从设备地址。at24c04模块设备地址 0x50和0x51是at24c04模块i2c芯片的设备地址。这个从芯片手册上也可以得知。A0 A1 A2表示的是模块对…

基于元模型优化算法的主从博弈多虚拟电厂动态定价和能量管理(matlab代码)

目录 1 主要内容 主从博弈模型 基于元模型的均衡算法流程图 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序复现《基于元模型优化算法的主从博弈多虚拟电厂动态定价和能量管理》模型&#xff0c;建立运营商和多虚拟电厂的一主多从博弈模型&#xff0c;研究运营商动态…

如何租用香港写字楼,需要注意哪些事项

1. 确定您的所需 你需要多少空间 在一切开始之前&#xff0c;您需要确切地知道您的业务(即您、您现有的员工和预计的招聘、您的访客或客户以及您想要的设施如食品储藏室、接待处、服务器机房甚至健身房&#xff0c;婴儿护理室等)&#xff0c;以实用面积计算需要多少空间。空间…

线性代数1:线性方程和系统

Digital Collection (staedelmuseum.de) 图片来自施泰德博物馆 一、前言 通过这些文章&#xff0c;我希望巩固我对这些基本概念的理解&#xff0c;同时如果可能的话&#xff0c;通过我希望成为一种基于直觉的数学学习方法为其他人提供额外的清晰度。如果有任何错误或机会需要我…

出差学小白知识No5:|Ubuntu上关联GitLab账号并下载项目(ssh key配置)

1 注冊自己的gitlab账户 有手就行 2 ubuntu安装git &#xff0c;并查看版本 sudo apt-get install git git --version 3 vim ~/.ssh/config Host gitlab.example.com User your_username Port 22 IdentityFile ~/.ssh/id_rsa PreferredAuthentications publickey 替换gitl…

C++多态的认识与理解

多态的概念 通俗来说&#xff0c;多态就是多种形态。具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生出不同的状态。 比方说买高铁票时&#xff0c;如果你是学生的话&#xff0c;买票就有优惠。如果你是军人的话&#xff0c;就可以优先买票。普通人的话&…

一文了解和使用nginx(附带图文)

前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 一文了解和使用nginx 一. nginx 简介1.1 什么是 nginx 和可以做什么事情1.2 正向代理1.3 反向代理1.4 负载均衡1.5 SSL 配置1.6 管理…

苹果官宣新品发布会 10月31日发布会与Mac有关

10 月 25 日消息&#xff0c;苹果宣布将于北京时间 10 月 31 日上午 8 点举行主题为“来势迅猛”的线上特别活动&#xff0c;届时或将有新品发布。 这场发布会与以往不同&#xff0c;将在北京时间 10 月 31 日上午 8 点举行。有很多猜测认为苹果届时会发布新款 Mac 电脑&#x…

Jenkins+Ant+Jmeter接口自动化集成测试

一、Jenkins安装配置 1、安装配置JDK1.6环境变量&#xff1b; 2、下载jenkins.war&#xff0c;放入C:\jenkins目录下&#xff0c;目录位置随意&#xff1b; Jenkins启动方法&#xff1a; cmd进入Jenkins目录下&#xff0c;执行java -jar jenkins.war 浏览器输入&#xff1a;l…

JavaSE 二叉树

目录 1 树型结构1.1 概念1.2 树的表示形式1.3 树的应用 2 二叉树2.1 概念2.2 二叉树的基本形态2.3 两种特殊的二叉树2.4 二叉树的性质2.5 二叉树的存储2.6 二叉树的基本操作2.6.1 二叉树的遍历2.6.2 二叉树的基本操作 2.7 基础练习题2.7.1 二叉树的前序遍历2.7.2 二叉树中序遍历…

TensorFlow2从磁盘读取图片数据集的示例(tf.data.Dataset.list_files)

import os import warnings warnings.filterwarnings("ignore") import tensorflow as tf from tensorflow.keras.optimizers import Adam from tensorflow.keras.applications.resnet import ResNet50 from pathlib import Path import numpy as np#数据所在文件夹 …

Unity C#中LuaTable、LuaArrayTable、LuaDictTable中数据的增删改查

LuaTable、LuaArrayTable、LuaDictTable中数据的增删改查 介绍Lua表lua表初始化lua移除引用lua中向表中添加数据lua中表中移除数据lua表中连接数据lua表中数据排序获取lua表长度获取表中最大值 UnityC#中LuaTableUnityC#中LuaArrayTable、LuaDictTable、LuaDictTable<K,V>…

Java游戏修炼手册:2023 最新学习线路图

前言 有没有一种令人兴奋的学习方法&#xff1f;当然有&#xff01;绝对有&#xff01;而且我要告诉你&#xff0c;学习的快乐可以媲美游戏的刺激。 小学时代&#xff0c;我曾深陷于一款名为"八百万勇士的梦"的游戏。每当放学&#xff0c;我总是迫不及待地打开电脑&a…

ES(elasticsearch) - 三种姿势进行分页查询

1. from size 浅分页 "浅"分页可以理解为简单意义上的分页。它的原理很简单&#xff0c;就是查询前20条数据&#xff0c;然后截断前10条&#xff0c;只返回10-20的数据。这样其实白白浪费了前10条的查询。 GET test_dev/_search {"query": {"bool&…

【tg】 7 GroupInstanceCustomImpl

group GroupInstanceCustomImpl 核心GroupInstanceCustomInternal G:\CDN\P2P-DEV\tdesktop-offical\Telegram\ThirdParty\tgcalls\tgcalls\group\GroupInstanceCustomImpl.h 最核心是是GroupInstanceCustomInternal: private:std::shared_ptr<Threads> _threads;std::u…

财报解读:步步逼近ChatGPT,科大讯飞即将迎来全面爆发?

10月份&#xff0c;科大讯飞进入新的成果验证节点。 一是进一步透露AI进展的财报发布。三季报显示&#xff0c;科大讯飞仍然保持较为稳健的发展步伐&#xff0c;营收始终处于增长状态&#xff0c;对讯飞星火认知大模型的应用成果&#xff0c;进行了进一步揭示。基于此&#xf…

基于LSTM encoder-decoder模型实现英文转中文的翻译机器

前言 神经网络机器翻译(NMT, neuro machine tranlation)是AIGC发展道路上的一个重要应用。正是对这个应用的研究&#xff0c;发展出了注意力机制&#xff0c;在此基础上产生了AIGC领域的霸主transformer。我们今天先把注意力机制这些东西放一边&#xff0c;介绍一个对机器翻译…

文心一言简单体验

百度正式发布文心一言&#xff0c;文心一言 这里的插件模式挺有意思&#xff1a; 测试了一下图解说明&#xff0c;随意上传了一张图片&#xff1a; 提供图解让反过来画&#xff0c;抓住了部分重点&#xff0c;但是还是和原图有比较大的差异&#xff01; 百宝箱 暂未逐个体验&am…

Linux ————​文件权限

&#xff08;一&#xff09;文件权限 基础补充 文件基本属性&#xff08;Linux中万物皆是文件&#xff09;文件是操作系统用来存储信息的基本结构&#xff0c;是一组信息的集合。文件通过文件名来唯一标识。Linux中的文件名称最长允许255个字符&#xff0c;这些字符可用A~Z、0…

【JAVA学习笔记】46 - (43)第十一章作业

项目代码 https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter11/src/com/yinhai/homework11 1.枚举类 1.创建一个Color枚举类 2.有RED,BLUE,BL ACK,YELLOW,GREEN这个五个枚举值/对象: 3. Color有三 个属性redValue, greenValue, blueValue, 4.创建构…