React类组件事件绑定this指向问题

900 阅读4分钟

react 类组件事件绑定 this 指向问题

一、React 类组件事件绑定方式:

1. 普通绑定

  • 直接调用
    class App extends React.Component{
        // 事件函数
        fn1(){
            console.log('fn1')
            console.log(this) // undefined
        }
        render(){
            <button onClick={ this.fn1 }>按钮1</button>
        }
    }
    
    • 单击 按钮1 ,控制台打印结果如下:

    image.png


this 指向 undefined ?

  • 利用 JS 类实验得到以下结果:

    // 定义 Star 类
    class Star {
        thisDirection() {
            console.log(this);
        }
    }
    
    var star = new Star();
    star.thisDirection(); // 实例调用
    const x = star.thisDirection; // 保存方法
    x(); // 直接调用
    
    • 控制台打印结果如下:

    image.png

    类中所有的方法,在局部默认开启了严格模式,它不敢指向 window 所以指向了 undefined


结论:在 React 事件普通绑定中,由于直接调用了类中的方法,所以 this 指向 undefined

2. bind 绑定:

  • 通过bind改变点击事件内的this指向外部组件内this (使用较多)
    class App extends React.Component{
       // 事件函数
       fn2(){
           console.log('fn2');
           console.log(this); // Class
       }
       render(){
           <button onClick={ this.fn2.bind(this) }>按钮2</button>
       }
    }
    
    • 单击 按钮2 ,控制台打印结果如下:

    image.png

  • 通过在构造函数constructor内使用bind对函数内的this重定向
    class App extends React.Component{
       constructor(){
           super() // ES6 类继承类, constructor() 里面用 this 必须调用 super() 函数
           // this 指向当前类组件
           // 调用公用的 属性 和 方法 必须加 this
           this.fn3 = this.fn3.bind(this)
       }
       // 事件函数
       fn3(){
           console.log('fn3');
           console.log(this); // Class
       }
       render(){
           <button onClick={ this.fn3 }>按钮3</button>
       }
    }
    
    • 单击 按钮3 ,控制台打印结果如下:

    image.png

3. 箭头函数绑定:

  • 通过使用箭头函数来指向外部组件内this (使用较多)
    class App extends React.Component{
        // 不是真实的事件函数
        fn4(){
            console.log('fn4');
            console.log(this); // Class
        }
        render(){
            // 箭头函数才是事件函数
            <button onClick={ () => this.fn4() }>按钮4</button>
        }
    }
    
    • 单击 按钮4 ,控制台打印结果如下:

    image.png

  • 将事件函数写成箭头函数来指向外部组件内this (使用较多)
    class App extends React.Component{
        fn5 = () => {
            console.log('fn5');
            console.log(this); 
        }
        render(){
            <button onClick={ this.fn5 }>按钮5</button>
        }
    }
    
    • 单击 按钮5 ,控制台打印结果如下:

    image.png

二、React 类组件事件绑定——事件对象:

  • 了解了 React 类组件事件绑定的 5 种方式,我们再来看看如何得到绑定事件的事件对象

1. 普通绑定

  • 直接调用
     class App extends React.Component{
         // 事件函数
         fn1(event){
             console.log('fn1')
             console.log(this) // undefined
             console.log(event); // 事件对象
         }
         render(){
             <button onClick={ this.fn1 }>按钮1</button>
         }
     }
    
    • 单击 按钮1 ,控制台打印结果如下:

    image.png

2. bind 绑定:

  • 通过bind改变点击事件内的this指向外部组件内this (使用较多)
    class App extends React.Component{
       // 事件函数
       fn2(event){
           console.log('fn2');
           console.log(this); 
           console.log(event);
       }
       render(){
           <button onClick={ this.fn2.bind(this) }>按钮2</button>
       }
    }
    
    • 单击 按钮2 ,控制台打印结果如下:

    image.png

  • 通过在构造函数constructor内使用bind对函数内的this重定向
    class App extends React.Component{
       constructor(){
           super() // ES6 类继承类, constructor() 里面用 this 必须调用 super() 函数
           // this 指向当前类组件
           // 调用公用的 属性 和 方法 必须加 this
           this.fn3 = this.fn3.bind(this)
       }
       // 事件函数
       fn3(event){
           console.log('fn3');
           console.log(this); 
           console.log(event);
       }
       render(){
           <button onClick={ this.fn3 }>按钮3</button>
       }
    }
    
    • 单击 按钮3 ,控制台打印结果如下:

    image.png

3. 箭头函数绑定:

  • 通过使用箭头函数来指向外部组件内this (使用较多)
    class App extends React.Component{
        // 不是真实的事件函数
        fn4(event){
            console.log('fn4');
            console.log(this); // Class
            console.log(event);
        }
        render(){
            // 箭头函数才是事件函数
            <button onClick={ (ev) => { this.fn4(ev); } }>按钮4</button>
        }
    }
    
    • 单击 按钮4 ,控制台打印结果如下:

    image.png

  • 将事件函数写成箭头函数来指向外部组件内this (使用较多)
    class App extends React.Component{
        fn5 = () => {
            console.log('fn5');
            console.log(this);
            console.log(event);
        }
        render(){
            <button onClick={ this.fn5 }>按钮5</button>
        }
    }
    
    • 单击 按钮5 ,控制台打印结果如下:

    image.png

三、React 类组件事件绑定——事件传参:

  • 得到了 React 类组件绑定事件的事件对象,我们再来看看如何对绑定事件传参

1. 普通绑定

  • 直接调用
     class App extends React.Component{
         render(){
             <button onClick={ this.fn1 }>按钮1</button>
         }
     }
    
    • 没有 () 无法传参

2. bind 绑定:

  • 通过bind改变点击事件内的this指向外部组件内this (使用较多)
    class App extends React.Component{
       // 事件函数
       fn2(num,event){
           console.log('fn2');
           console.log(this); 
           console.log(num);
           console.log(event);
       }
       render(){
           <button onClick={ this.fn2.bind(this, 200) }>按钮2</button>
       }
    }
    
    • 单击 按钮2 ,控制台打印结果如下:

    image.png

  • 通过在构造函数constructor内使用bind对函数内的this重定向
    class App extends React.Component{
       render(){
           <button onClick={ this.fn3 }>按钮3</button>
       }
    }
    
    • 没有 () 无法传参

3. 箭头函数绑定:

  • 通过使用箭头函数来指向外部组件内this (使用较多)
    class App extends React.Component{
        // 不是真实的事件函数
        fn4(){
            console.log('fn4');
            console.log(this); // Class
            console.log(num);
            console.log(event);
        }
        render(){
            // 箭头函数才是事件函数
            <button onClick={ (ev) => { this.fn4(ev); } }>按钮4</button>
        }
    }
    
    • 单击 按钮4 ,控制台打印结果如下:

    image.png

  • 将事件函数写成箭头函数来指向外部组件内this (使用较多)
    class App extends React.Component{
        render(){
            <button onClick={ this.fn5 }>按钮5</button>
        }
    }
    
    • 没有 () 无法传参

总结:

一、直接绑定事件函数,会丢失 this 指向,为了解决这个问题,React 提供了如下方式:

1. bind 绑定
2. 箭头函数绑定

二、既传参又获取事件对象只有两种方式可以实现:

1. 模板里面 bind 绑定事件传参
2. 箭头函数作为事件函数绑定事件传参