react的事件處理為什么要bind this 改變this的指向?


 

react的事件處理會丟失this,所以需要綁定,為什么會丟失this?

 

首先來看摘自官方的一句話:

You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default.

  

這句話大概意思就是,你要小心jax回調函數里面的this,class方法默認是不會綁定它的

讓我十分疑惑,在我的知識范圍理解中,class是es6里面新增的方法,不就用來繼承原有對象上的屬性和方法創建新的對象嗎?就是代替原來的構造函數的一種更清晰的方式,為什么就不會綁定this呢?

 

可是查閱了一些es6的文檔,並不是這樣的啊,和class方法沒啥關系吧,為什么要它背鍋呢?

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}> //這里調用的this也能拿到啊??
        {this.state.isToggleOn ? 'ON' : 'OFF'} //這里的this為什么沒問題?
      </button>
    );
  }
}

  

這是官網上的一段代碼,如果是是因為class的關系,handleClick里面拿不到this,那為什么render里面能拿到this,所以和class根本沒關系吧本來就能拿到,那問題出現在哪里,為什么拿不到?

 

先看看解決辦法

第一種,在constructor里面用bind綁定this

constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }

第二種,聲明方法的時候使用箭頭函數

  handleClick = () => {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

第三種,調用的時候使用箭頭函數

render() {
    return (
      <button onClick={ () => { this.handleClick } }> 
        {this.state.isToggleOn ? 'ON' : 'OFF'} 
      </button>
    );
  }

  這個時候我想起了原生dom綁定click的方法

<button onclick ="handleClick()">點我</button>

  

  兩者比較,我發現了個區別,原生的綁定方法事件名后面多了個()
於是我嘗試着在react里面的事件加一個()

render() {
    return (
      <button onClick={ this.handleClick() }> 
        {this.state.isToggleOn ? 'ON' : 'OFF'} 
      </button>
    );
  }
就像上面這樣,然后我發現,無論我怎么點,都不會觸發這個方法了,再細心點,就發現,在渲染的時候,就調用了一次,而且僅此一次,再也不能調用了.

原因是jsx語法,渲染的時候會把{}里面包裹的代碼先解析一遍,因為如果加了括號,直接就執行了里面的函數,就沒有東西了,但是這個時候,this是可以拿到的
class App extends Component {
  handleClick(){
      console.log(this); //下面調用加了(),這個時候發現,this是可以拿到的
  }
  render() {
    return (
      <div className="App">
        <button onClick={this.handleClick()}>點我</button> //這里加了括號的
      </div>
    );
  }
}

  好像問題越來越明朗了,為啥會拿不到,和class沒有關系,完全是因為react自己封裝的東西,先會把{}里面的代碼解析一遍,於是大概就是下面這種情況了

const obj = {
        num:1
    }
    obj.handleClick = function () {
        console.log(this);
    }
    console.log(eval(obj.handleClick ));  // f(){ console.log(this) } react對{}的解析
    (eval(obj.handleClick))() //onclick觸發點擊事件 這里輸出this是window,所以就等於丟失了this指向

    console.log(eval(() => { obj.handleClick() }));  // () => { obj.handleClick() } react對{}的解析
    (eval(() => {obj.handleClick()}))() //onclick觸發點擊事件 這里輸出this還是obj,所以this就保留了

  所以問題出在react對{}的解析會把this的指向解除了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM