react 类组件当中解决this指向问题的一些方案 以及this指向情况

322 阅读2分钟

1 问题 实现一个点击按钮数值加1的案列

image.png



class App extends Component {
    state = {
        count: 0,
    }
    handleClick() {
        // Cannot read properties of undefined (reading 'state')
        console.log(this.state.count)
    }
    render() {
        return (
            <div>
                <h2>计数器:{this.state.count}</h2>
                <button onClick={this.handleClick}>+1</button>
            </div>
        )
    }
}

这样在handleClick函数中的 this 是undefined(因为类中默认开启严格模式) 函数独立调用 this 就是 undefined

2 解决方法

1. 直接调用 事件接收返回值 为一个箭头函数 箭头函数 this 为定义他的父级函数 父级函数又被实例调用 所以箭头函数指向实例
 handleClick() {
        // 这里的 this 指向是什么?那就看是谁调用的!
        return () => {
            console.log(this.state.count)
             let { count } = this.state
            console.log(count);
            this.setState({ count: count + 1 })
        }
    }
    render() {
        return (
            <div>
                <h2>计数器:{this.state.count}</h2>
                <button onClick={this.handleClick()}>+1</button>
            </div>
        )
    }
2 通过 bind 改变函数的 this 指向 让其指向实例
 handleClick() {
        //1 // 这里的 this 指向是什么?那就看是谁调用的!
        let { count } = this.state
        console.log(count);
        this.setState({ count: count + 1 })
    }

    render() {
        return (
            <div>
                <h2>计数器:{this.state.count}</h2>
                <button onClick={this.handleClick.bind(this)}>+1</button>
            </div>
        )
    }

3 this 调用处理函数 而这里的 this 又是实例 让擦护理函数的 this 指向实例
  handleClick() {
        //1 // 这里的 this 指向是什么?那就看是谁调用的!
        // return () => {
        //     console.log(this.state.count)
        // }
        //2  bind
        console.log(this.state.count);
         let { count } = this.state
        console.log(count);
        this.setState({ count: count + 1 })

    }
    render() {
        return (
            <div>
                <h2>计数器:{this.state.count}</h2>
                <button onClick={() => this.handleClick()}>+1</button>
            </div>
        )
    }
4 改用箭头函数 并将方法作为实例属性 这样内部的 this 就指向的实例
 handleClick = () => {
        //1 // 这里的 this 指向是什么?那就看是谁调用的!
        let { count } = this.state
        console.log(count);
        this.setState({ count: count + 1 })
        // setState 是合并操作 不会影响没操作的数据 并不是直接覆盖了
    }

    render() {
        return (
            <div>
                <h2>计数器:{this.state.count}</h2>
                <button onClick={this.handleClick}>+1</button>
            </div>
        )
    }
5

(1)往实例自身上又挂载了一个 handleClick 函数 ,
(2) 此函数的函数体是通过原型上 handleClick 函数生成的新函数,
(3)并把原型上 handleClick 函数中的 this 通过 bind 绑定为了 this,而这里构造函数中的 this 正是实例对象,
(4)其实点击的时候调用的是这个构造函数 handleClick(就近原则),而这个构造函数中的 handleClick 执行的是原型上的 handleClick 的函数体


class App extends React.Component {
    constructor() {
        super()
        this.state = {
            count: 0,
        }
       
        this.handleClick = this.handleClick.bind(this)
    }
    handleClick() {
        console.log(this.state.count)
         let { count } = this.state
        console.log(count);
        this.setState({ count: count + 1 })
    }
    render() {
        return (
            <div>
                <h2>计数器:{this.state.count}</h2>
                <button onClick={this.handleClick}>+1</button>
            </div>
        )
    }
}

这五种方法都可以用来解决 this 指向的问题
在非严格模式下 this 的情况有 :
1 。默认绑定规则(在window上) 独立调用 this就是指向window(包括立即执行函数)
2。隐式绑定(谁调用指向谁)
3.显式绑定 (通过call(),apply(),bind()来强制绑定到相应的对象上)
4通过new 构造函数(指向new实例出来的对象)
具体的执行看函数的执行方式,不看函数的定义
注意: 箭头函数没有自己的this,没有原型,没有augment,任何方法都改变不了其指向this指向 。箭头函数的this是在定义函数时绑定的,不是在执行过程中绑定的。果箭头函数被非箭头函包含,则this绑定指向的是最近一层父级非箭头函数的this,否则,this的值会被设置为全局对象。