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       }
复制代码

 

posted @   Eric-Shen  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示