React(二):JSX语法解析+综合案例

news2025/3/18 15:29:20

事件绑定

this绑定方式

问题:在事件执行后,需获取当前类的对象中相关属性,此时需要this——当打印时,发现this为undefined,这又是为啥?

假设有一个btnClick函数,但它并不是我们主动调用的,而是当button发生改变时,React内部调用→内部调用时,并不知道要如何绑定正确的this

解决办法:

  1. bind给btnClick显示绑定this
  2. 使用 ES6 class fields 语法
  3. 事件监听时传入箭头函数(较为推荐)
<body>
  <div id="root"></div>

  <script src="../lib/react.js"></script>
  <script src="../lib/react-dom.js"></script>
  <script src="../lib/babel.js"></script>

  <script type="text/babel">
    /* 
    this的四种绑定规则 
     1.默认绑定:独立执行foo()
     2.隐式绑定:被一个对象执行obj.foo() ->obj
     3.显示绑定:call/apply/bind  foo.call('aaa') ->String('aaa')
     4.new绑定:new Foo() -> 创建一个新对象,并赋值给this
    */
    //1.创建root
    const root = ReactDOM.createRoot(document.getElementById('root'))

    //2..定义App根组件
    class App extends React.Component {
      constructor() {
        super()

        this.state = {
          count:100
        }
      }

      btn1Click() {
        this.setState({ 
          count:this.state.count+1
        })
      }

      // 箭头函数无this,只能去上一层找
      btn2Click = () => {
        this.setState({ 
          count:this.state.count-1
        })
      }

      btn3Click() {
        this.setState({ 
          count:this.state.count-1
        })
      }

      render(){
        const {count} = this.state
        return (
          <div>
            <h1>{ count }</h1>
            {/* 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>
          </div>
        )
      }
    }

    // 3.将App组件渲染到root上
    root.render(<App />)
  </script>
</body>
事件参数传递

1.获取默认参数:即event对象

2.获取更多参数:可通过传入一个箭头函数,主动执行的事件函数,并且传入相关的其他参数

<body>
  <div id="root"></div>

  <script src="../lib/react.js"></script>
  <script src="../lib/react-dom.js"></script>
  <script src="../lib/babel.js"></script>

  <script type="text/babel">
    //1.创建root
    const root = ReactDOM.createRoot(document.getElementById('root'))

    //2..定义App根组件
    class App extends React.Component {
      constructor() {
        super()

        this.state = {
          message:"Hello World"
        }
      }

      btnClick (event,name,age) {
        console.log("点击事件", event,this);
        console.log("name:", name, "age:",age);
      }

      render(){
        const {message} = this.state
        return (
          <div>
            {/* 1.event参数的传递 */}
            <button onClick={this.btnClick}>按钮1</button>
            <button onClick={(event) => this.btnClick(event)}>按钮2</button>

            {/* 2.传递额外的参数 */}
            <button onClick={(event) => this.btnClick(event, "why", 30)}>按钮3</button>
          </div>
        )
      }
    }

    // 3.将App组件渲染到root上
    root.render(<App />)
  </script>
</body>

条件渲染

在vue中,我们会通过指令来控制:比如v-if、v-show;

在React中,所有的条件判断都和普通的JavaScript代码一致;

常见条件渲染方式:

1.条件判断语句

2.三元运算符

3.与运算符&&

<body>
  <div id="root"></div>

  <script src="../lib/react.js"></script>
  <script src="../lib/react-dom.js"></script>
  <script src="../lib/babel.js"></script>

  <script type="text/babel">
    //1.创建root
    const root = ReactDOM.createRoot(document.getElementById('root'))

    //2..定义App根组件
    class App extends React.Component {
      constructor() {
        super()

        this.state = {
          isReady:true,

          friend:{
            name:"lucy",
            age:22,
            gender:"女"
          }
        }
      }

      render(){
        const {isReady,friend} = this.state
        // 1.条件判断方式一:使用if进行条件判断
        let showElement = null
        if(isReady) {
          showElement = <h2>准备开始比赛吧</h2>
        }else{
          showElement = <h1>我还没有准备好嘞</h1>
        }
        return (
          <div>
            {/* 方式一:根据条件给变量赋值不同的内容 */}
            <div>{ showElement }</div>

            {/* 方式二:三元运算符 */}
            <div>{isReady? <button>准备开始</button> : <button>还没有准备好</button> }</div>

            {/* 方式三:&&运算符 */}
            {/* 场景:当某一个值,有可能为undefined时,使用&&进行条件判断 */}
            <div>{ friend && <div>{friend.name + friend.age + friend.gender}</div> }</div>
          </div>
        )
      }
    }

    // 3.将App组件渲染到root上
    root.render(<App />)
  </script>
</body>

实现v-show的效果:

class App extends React.Component {
  constructor() {
    super()

    this.state = {
      message:"Hello World",
      isShow:true
    }
  }

  ediClick() {
    this.setState({
      isShow:!this.state.isShow
    })
  }
  render(){
    const {message,isShow} = this.state
    return (
      <div>
        <button onClick={this.ediClick.bind(this)}>切换1</button>
        <h1 >{ isShow? message : "" }</h1>

        {/* v-show的效果 */}
        <button onClick={this.ediClick.bind(this)}>切换2</button>
        <h1 style={{display:isShow ? "block" : "none"}}>{ message }</h1>
      </div>
    )
  }
}

列表渲染

class App extends React.Component {
  constructor() {
    super()

    this.state = {
      students:[
        {id:1, name:'Jack', age:18},
        {id:2, name:'Tom', age:20},
        {id:3, name:'Lucy', age:22},
        {id:4, name:'Lily', age:24}
      ]
    }
  }

  render(){
    const {students} = this.state

    // 展示年龄大于20的
    const filterStudents = students.filter(item => item.age >= 20)
    return (
      <div>
        <h2>学生信息列表</h2>
        <div className="list">
          {/* 绑定唯一标识key:提高diff算法时的效率 */}
          {filterStudents.map(item => 
            <div key={item.id} className="item">
              <p>id:{item.id}</p>
              <p>姓名:{item.name}</p>
              <p>年龄:{item.age}</p>
            </div>
          )}
        </div>
      </div>
    )
  }
}

原理本质

babel转换

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

createElement需要传递三个参数:

1.参数一:type

  • 当前ReactElement的类型;
  • 如果是标签元素,那么就使用字符串表示 “div”;
  • 如果是组件元素,那么就直接使用组件的名称;

2.参数二:config

  • 所有jsx中的属性都在config中以对象的属性和值的形式存储;
  • 比如传入className作为元素的class;

3.参数三:children

  • 存放在标签中的内容,以children数组的方式进行存储;

直接编写jsx代码:

<div>
  <div className="header">header</div>
  <div className="Content">
    <div>Banner</div>
    <ul>
      <li>数据列表1</li>
      <li>数据列表2</li>
      <li>数据列表3</li>
    </ul>
  </div>
  <div className="footer">footer</div>
</div>

经过babel转译后:

React.createElement(
'div',
null,
React.createElement('div', { className: 'header' }, 'header'),
React.createElement(
  'div',
  { className: 'Content' },
  React.createElement('div', null, 'Banner'),
  React.createElement(
    'ul',
    null,
    React.createElement('li', null, '数据列表1'),
    React.createElement('li', null, '数据列表2'),
    React.createElement('li', null, '数据列表3')
  )
),
React.createElement('div', { className: 'footer' }, 'footer')
);
虚拟DOM生成

通过React.createElement最终创建出一个ReactElement对象→它组成了一个JS对象树→即虚拟DOM

阶段案例-购物车

<body>
  
  <div id="root"></div>

  <script src="../lib/react.js"></script>
  <script src="../lib/react-dom.js"></script>
  <script src="../lib/babel.js"></script>

  <script src="./data.js"></script>
  <script src="./format.js"></script>

  <script type="text/babel">
    // 1.定义App根组件
    class App extends React.Component {
      constructor() {
        super()
        this.state = {
          books: books
        }
      }

      getTotalPrice() {
        const totalPrice = this.state.books.reduce((preValue, item) => {
          return preValue + item.count * item.price
        }, 0)
        return totalPrice
      }

      changeCount(index, count) {
        const newBooks = [...this.state.books]
        newBooks[index].count += count
        this.setState({ books: newBooks })
      }

      removeItem(index) {
        const newBooks = [...this.state.books]
        newBooks.splice(index, 1)
        this.setState({ books: newBooks })
      }

      renderBookList() {
        const { books } = this.state

        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>{index + 1}</td>
                      <td>{item.name}</td>
                      <td>{item.date}</td>
                      <td>{formatPrice(item.price)}</td>
                      <td>
                        <button 
                          disabled={item.count <= 1}
                          onClick={() => this.changeCount(index, -1)}
                        >
                          -
                        </button>
                        {item.count}
                        <button onClick={() => this.changeCount(index, 1)}>+</button>
                      </td>
                      <td><button onClick={() => this.removeItem(index)}>删除</button></td>
                    </tr>
                  )
                })
              }
            </tbody>
          </table>
          <h2>总价格: {formatPrice(this.getTotalPrice())}</h2>
        </div>
      }

      renderBookEmpty() {
        return <div><h2>购物车为空, 请添加书籍~</h2></div>
      }

      render() {
        const { books } = this.state
        return books.length ? this.renderBookList(): this.renderBookEmpty()
      }
    }

    // 2.创建root并且渲染App组件
    const root = ReactDOM.createRoot(document.querySelector("#root"))
    root.render(<App/>)
  </script>

</body>

format.js(数值格式化文件)

function formatPrice(price) {
  return "¥" + Number(price).toFixed(2)
}

data.js(数据文件) 

const books = [
  {
    id: 1,
    name: '《算法导论》',
    date: '2006-9',
    price: 85.00,
    count: 1
  },
  {
    id: 2,
    name: '《UNIX编程艺术》',
    date: '2006-2',
    price: 59.00,
    count: 1
  },
  {
    id: 3,
    name: '《编程珠玑》',
    date: '2008-10',
    price: 39.00,
    count: 1
  },
  {
    id: 4,
    name: '《代码大全》',
    date: '2006-3',
    price: 128.00,
    count: 1
  },
]

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

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

相关文章

Gitee重新远程连接仓库(Linux)

Gitee重新远程连接仓库&#xff08;Linux&#xff09; 因为虚拟机重新安装了一回&#xff0c;所以需要重新和远程仓库连接&#xff0c;在网上找了很久没有找到相关操作&#xff0c;自己实操成功&#xff0c;记录下本博客&#xff0c;帮助有需要的人 确保新虚拟机安装Git 在新虚…

Vitis HLS中的Array Partition与Array Reshape详解

Vitis HLS中的Array Partition与Array Reshape详解 引言 在高层次综合(HLS)设计中&#xff0c;数组是最常用的数据结构之一&#xff0c;但默认情况下&#xff0c;HLS会将数组映射到单个BRAM块&#xff0c;这会限制并行访问能力&#xff0c;成为性能瓶颈。为了克服这一限制&am…

Centos离线安装openssl

文章目录 Centos离线安装openssl1. openssl是什么&#xff1f;2. openssl下载地址3. openssl-devel安装4. 安装结果验证5. 版本查看 Centos离线安装openssl 1. openssl是什么&#xff1f; OpenSSL 是一个开源的、跨平台的 加密工具库 和 命令行工具集&#xff0c;广泛用于实现…

protobuf安装

安装 github官方链接 https://github.com/protocolbuffers/protobuf/ 以protobuf21为例 https://github.com/protocolbuffers/protobuf/releases/download/v21.11/protobuf-all-21.11.zip windows 解压好文件夹后,使用cmake,vs,qt creator等工具打开该项目,进行编译,编译需…

《基于超高频RFID的图书馆管理系统的设计与实现》开题报告

一、研究背景与意义 1.研究背景 随着信息化时代的到来&#xff0c;运用计算机科学技术实现图书馆的管理工作已成为优势。更加科学地管理图书馆会大大提高工作效率。我国的图书管理体系发展经历了三个阶段&#xff1a;传统图书管理模式、现代图书管理模式以及基于无线射频识别&…

小程序渲染之谜:如何解决“加载中...”不消失的 Bug(glass-easel)

&#x1f389; 小程序渲染之谜&#xff1a;如何解决“加载中…”不消失的 Bug &#x1f389; 引言 在小程序开发中&#xff0c;渲染问题总能让人抓狂。&#x1f62b; 这次&#xff0c;我遇到了一个奇怪的 bug&#xff1a;产品详情页的内容已经正常显示&#xff0c;但页面却一…

网络原理之HTTPS(如果想知道网络原理中有关HTTPS的知识,那么只看这一篇就足够了!)

前言&#xff1a;随着互联网安全问题日益严重&#xff0c;HTTPS已成为保障数据传输安全的标准协议&#xff0c;通过加密技术和身份验证&#xff0c;HTTPS有效防止数据窃取、篡改和中间人攻击&#xff0c;确保通信双方的安全和信任。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要…

五子棋小游戏-简单开发版

一、需求分析 开发一个基于 Pygame 库的五子棋小游戏&#xff0c;允许两名玩家在棋盘上轮流落子&#xff0c;当有一方达成五子连珠时游戏结束&#xff0c;显示获胜信息&#xff0c;并提供退出游戏和重新开始游戏的操作选项。 1.棋盘显示 &#xff1a; 显示一个 15x15 的五子棋…

2025中国科技大学少年班/创新试点班·初试备考测试卷(数学)

本卷考查内容&#xff1a;高中课程内容及拓展。 本卷考查形式&#xff1a;书面作答&#xff08;客观题18小题解答题4题&#xff09;。 卷首语&#xff1a;中科大少年班、创新班每年大规模招录在数理成绩优异的中学学生。其中初试数学题在高考基础上略有拓展&#xff0c;难度又低…

即时通讯平台测试报告

1.项目概述 项目名称&#xff1a;即时通讯平台 版本号&#xff1a;V1.0.0 测试周期&#xff1a;2025年2月25日--2025年3月15日 测试目标&#xff1a;验证核心功能&#xff08;登录、注册、消息收发、用户管理、群组功能等&#xff09;的稳定性和性能指标。 2. 测试范围 功…

如何记录Matlab程序运行过程中所占用的最大内存

有些时候&#xff0c;我们需要分析Matlab程序运行过程中所占用的最大内存。如果只是得到程序运行到当前位置所占用的内存&#xff0c;可以简单在程序当前位置插入memory命令即可&#xff1a; user memory; MemUsed_now user.MemUsedMATLAB; 但如果我们想要的是整个程序在运行…

WIN11开发环境变量记录

这里写自定义目录标题 总图JAVA环境变量配置GIT环境变量配置NODEJS环境变量配置 总图 JAVA环境变量配置 新建系统变量。变量名&#xff1a;JAVA_HOME&#xff0c;变量值&#xff08;可以选择浏览目录&#xff0c;JAVA的根目录&#xff0c;本处为D:\Java\jdk1.8.0_251&#xff…

易语言模拟真人鼠标轨迹算法

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序&#xff0c;它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言&#xff0c;原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势&#xff1a; 模拟…

洛谷P9950 [USACO20FEB] Mad Scientist B

P9950 [USACO20FEB] Mad Scientist B - 洛谷 代码区&#xff1a; #include <iostream> #include <string>using namespace std; int main() {int n;cin>> n;string a;string b;cin >> a >> b;int flag,step0,i,t;for ( i 0; i < a.length(…

prometheus自定义监控(pushgateway和blackbox)和远端存储VictoriaMetrics

1 pushgateway采集 1.1 自定义采集键值 如果自定义采集需求时&#xff0c;就可以通过写脚本 定时任务定期发送数据到 pushgateway 达到自定义监控 1.部署 pushgateway&#xff0c;以 10.0.0.42 节点为例 1.下载组件 wget https://github.com/prometheus/pushgateway/relea…

C++相关基础概念之入门讲解(上)

1. 命名空间 C中的命名空间&#xff08;namespace&#xff09;是用来避免命名冲突问题的一种机制。通过将类、函数、变量等封装在命名空间中&#xff0c;可以避免不同部分的代码中出现相同名称的冲突。在C中&#xff0c;可以使用namespace关键字来定义命名空间。 然后我们在调…

【大模型】Transformer、GPT1、GPT2、GPT3、BERT 的论文解析

前言 在自然语言处理&#xff08;NLP&#xff09;和深度学习的快速发展中&#xff0c;Transformer模型和 GPT系列模型扮演了至关重要的角色。本篇博客旨在对这些开创性的论文进行介绍&#xff0c;涵盖它们的提出时间、网络结构等关键信息&#xff0c;能够快速的理解这些模型的设…

【Java 优选算法】分治-归并排序

欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 数组分块如二叉树的前序遍历, 而归并排序就如二叉树的后序遍历 912. 排序数组 解法 使用归并算法 根据中间点划分区间, mid (right left ) / 2将左右区间排序合并两个有…

三格电子Modbus TCP转CANOpen网关相关问答

型号&#xff1a;SG-TCP-COE-210 Q1: Modbus TCP转CANOpen网关的主要功能是什么&#xff1f; A1: 该网关的核心功能是实现 Modbus TCP协议与CANOpen协议之间的双向数据转换&#xff0c;使支持Modbus TCP的工业设备&#xff08;如PLC、HMI&#xff09;能够与基于CANOpen协议的设…

Flutter FloatingActionButton 从核心用法到高级定制

目录 1. 引言 2. FloatingActionButton 的基本用法 3. 主要属性 4. 进阶定制技巧 4.1 扩展型 FAB 4.2 动态变形动画 4.3 多个 FAB 协同 5. 主题与动效集成 5.1 全局主题配置 5.2 平台适配方案 5.3 高级动画控制器 6. 最佳实践 6.1 布局规范 6.2 性能优化 6.3 无…