React—03—类组件中事件处理函数的this绑定、事件处理函数的传参;jsx的条件判断渲染;jsx的循环渲染
零、如何给html元素加事件监听
1.原生方式:通过querySelector()方法,捕捉到元素,比如说button元素,然后通过btn.onclick = () =>{}或者通过btn.addEventListensers('click', ()=>{})的方式
2.vue的模板语法糖,在元素上使用v-on指令,比如@click
3.react的模板语法糖,在元素上使用事件onClick,注意这个是小驼峰,和原生的不一样原生的全部小写。
一、解决jsx事件绑定函数的this指向:
问题:为什么在btn1Click函数中,this是undefined?
思考:谁调用的,this就指向谁;在这里,我们通过this.btn1Click把函数地址赋值给了button元素(注意,这里可以不是App类实例调用了btn1Clcik,我们只是获取了函数的堆地址,然后赋值给了button元素的click事件,如果是App类实例调用调用
那应该是this.btn1Click()而不是this.btn1Click,没有执行只是获取地址)
所以,直接调用btn1Click函数的是button元素,经过babel.js把jsx编译后本质上是React.createElement('button',{ onClick:this.btn1Click }), 然后后面再调用的时候react会把btn1Click赋值给一个常量const xxx = btn1Click; 后续react会直接通过xxx()的方式调用,那么在非严格环境中比如浏览器环境中this指向的是window,但是在严格环境中比如babel.js进行编译的那就是undefined。
而现在,jsx就是用babel.js解析的,babel.js转换后的代码自动加上 use strict ,自动变成了严格模式。。
原因: this是谁调用指向谁,经过babel转化和react实际上是直接调用 ,因此指向undefined。
class App extends React.Component { constructor() { super(); this.state = { conuter: 100 }; //解决方案一的另外一种方式: 使用bind函数 // this.btn1Click = this.btn1Click.bind(this); } btn1Click() { console.log('按钮1被点击了', this); this.setState({ conuter: this.state.conuter + 1 }); } btn2Click = () => { console.log('按钮2被点击了', this); this.setState({ conuter: this.state.conuter + 10 }); }; btn3Click(){ console.log('按钮3被点击了', this); this.setState({ conuter: this.state.conuter + 100 }); } render() { const { conuter } = this.state; return ( <div> <h2>计算器:{conuter}</h2> {/* 解决方案一: 使用bind绑定 使用bind函数绑定事件处理函数,将会返回一个新的函数;在button元素执行这个新函数时,新函数将会执行btn1Click函数并且将btn1Click函数的this牢牢指向App组件的this */} <button onClick={this.btn1Click.bind(this)}>按钮1</button> {/* 解决方案二: 事件处理函数改为箭头函数 箭头函数的this指向父级作用域的this,所以箭头函数的this指向App组件的this */} <button onClick={this.btn2Click}>按钮2</button> {/* 解决方案三: 传入箭头函数 由于btn3Click函数还是this调用的,所以还会指向this; */} <button onClick={() => this.btn3Click()}></button> </div> ); } }
我个人感觉方案一和方案三有点类似,它们的解决哲学都是在外面再包裹一个函数比如a,然后事件处理函数b在a里面执行,在a里面给b做操作使得b的this指向发生改变。
二、解决jsx事件绑定函数的传参
推荐使用箭头函数,默认参数event,还有自定义参数name、age等都可以很方便的传递给事件处理函数btnClick。
class App extends React.Component { constructor() { super(); this.state = { conuter: 100 }; } btnClick(event, name, age) { console.log('按钮1被点击了', this); console.log(event, name, age); } render() { const { conuter } = this.state; return ( <div> <button onClick={event => this.btnClick(event, 'kobe', 18)}>按钮</button> </div> ); } }
传参的时候我写了一段错误代码:
主要是回调函数调用不熟悉,onClick={(event, index) => this.handleClick()}是原生div回调,除了传event参数,跟本就不会传index参数。
render() { const { header, currentIndex } = this.state; return ( <div> <div className="head-container"> {header.map((e, index) => { // 错误:div调用原生click事件回调函数时,只会传递event参数,这个搞个index参数div元素又不传递,那不就是undefined吗? // 然后this.handleClick(index)里这个index因为函数参数里已经命名了,所以直接取这个undefined,就不会取map函数的index参数了, // 所以传递了一个undefined到handleClick()函数中,所以就会报错了 // return ( // <div className={currentIndex === index ? 'active' : ''} onClick={(event, index) => this.handleClick(index)}> // {e} // </div> // ); return ( <div className={currentIndex === index ? 'active' : ''} onClick={() => this.handleClick(index)}> {e} </div> ); })} </div> <p>{header[currentIndex]}</p> </div> ); }
三、条件判断
由于jsx就是js的拓展,所以直接用js的if、三元运算符、短路与等操作符即可,不需要像vue一样使用v-if指令。
1 class App extends React.Component { 2 constructor() { 3 super(); 4 this.state = { 5 isReady: false 6 }; 7 } 8 9 render() { 10 const { isReady } = this.state; 11 12 let showText = null; 13 14 if (isReady) showText = <h2>请战斗吧</h2>; 15 else showText = <h2>请抓紧准备</h2>; 16 17 //if else判断 18 //return <div>{showText}</div>; 19 20 // 三目运算符 21 // return <div>{isReady ? <h2>请战斗吧</h2> : <h2>请抓紧准备</h2>}</div>; 22 23 // 逻辑与运算符 24 return <div>{isReady && <h2>请战斗吧</h2>}</div>; 25 26 } 27 }
四、循环渲染
由于jsx就是js的拓展,所以直接用js的map去渲染元素即可,不需要像vue一样使用v-for指令。
注意,在元素内使用js代码要用{}。
1 class App extends React.Component { 2 constructor() { 3 super(); 4 this.state = { 5 students: [ 6 { 7 name: '张三', 8 age: 18, 9 sex: '男' 10 }, 11 { 12 name: '李四', 13 age: 19, 14 sex: '女' 15 }, 16 { 17 name: '王五', 18 age: 20, 19 sex: '男' 20 } 21 ] 22 }; 23 } 24 25 render() { 26 const { students } = this.state; 27 28 return ( 29 <div> 30 学生列表: 31 <div className="container"> 32 {students 33 .filter(e => e.age >= 19) 34 .slice(0, 2) 35 .map(e => ( 36 <div className="item"> 37 <p>{e.name}</p> 38 <p>{e.age}</p> 39 <p>{e.sex}</p> 40 </div> 41 ))} 42 </div> 43 </div> 44 ); 45 } 46 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!