冬日炉火 發表於 2019-7-24 08:45:00

react的事件处理为什么要bind this 改变this的指向?

<h2>&nbsp;</h2>
<h2><strong>react的事件处理会丢失this,所以需要绑定,为什么会丢失this?</strong></h2>
<h3>&nbsp;</h3>
<h3><strong>首先来看摘自官方的一句话:</strong></h3>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default.
</pre>
</div>
<p>  </p>
<div>
<div>
<p><span style="font-size: 12px">这句话大概意思就是,你要小心jax回调函数里面的this,class方法默认是不会绑定它的</span></p>
<p><span style="font-size: 12px">让我十分疑惑,在我的知识范围理解中,class是es6里面新增的方法,不就用来继承原有对象上的属性和方法创建新的对象吗?就是代替原来的构造函数的一种更清晰的方式,为什么就不会绑定this呢?</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-size: 18px">可是查阅了一些es6的文档,并不是这样的啊,和class方法没啥关系吧,为什么要它背锅呢?</span></strong></p>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">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 =&gt; ({
      isToggleOn: !prevState.isToggleOn
    }));
}

render() {
    return (
      &lt;button onClick={this.handleClick}&gt; //这里调用的this也能拿到啊??
      {this.state.isToggleOn ? 'ON' : 'OFF'} //这里的this为什么没问题?
      &lt;/button&gt;
    );
}
}

</pre>
</div>
<p>  </p>
<div>
<div>
<p><span style="font-size: 12px">这是官网上的一段代码,如果是是因为class的关系,handleClick里面拿不到this,那为什么render里面能拿到this,所以和class根本没关系吧本来就能拿到,那问题出现在哪里,为什么拿不到?</span></p>
<p>&nbsp;</p>
<p><span style="font-size: 18pt"><strong>先看看解决办法</strong> </span></p>
<h2>第一种,在constructor里面用bind绑定this</h2>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">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);
}
</pre>
</div>
<h2>第二种,声明方法的时候使用箭头函数</h2>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">handleClick = () =&gt; {
    this.setState(prevState =&gt; ({
      isToggleOn: !prevState.isToggleOn
    }));
}
</pre>
</div>
<h2>第三种,调用的时候使用箭头函数</h2>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">render() {
    return (
      &lt;button onClick={ () =&gt; { this.handleClick } }&gt;
      {this.state.isToggleOn ? 'ON' : 'OFF'}
      &lt;/button&gt;
    );
}
</pre>
</div>
<p><span style="font-size: 12px">  这个时候我想起了原生dom绑定click的方法</span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">&lt;button onclick ="handleClick()"&gt;点我&lt;/button&gt;
</pre>
</div>
<p><span style="font-size: 18px">  </span></p>
<p><span style="font-size: 12px">  两者比较,我发现了个区别,原生的绑定方法事件名后面多了个()</span><br><span style="font-size: 12px">于是我尝试着在react里面的事件加一个()</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">render() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
      </span>&lt;button onClick={ <span style="color: rgba(0, 0, 255, 1)">this</span>.handleClick() }&gt;<span style="color: rgba(0, 0, 0, 1)">
      {</span><span style="color: rgba(0, 0, 255, 1)">this</span>.state.isToggleOn ? 'ON' : 'OFF'<span style="color: rgba(0, 0, 0, 1)">}
      </span>&lt;/button&gt;
<span style="color: rgba(0, 0, 0, 1)">    );
}</span></pre>
</div>
<div>
<div><span style="font-size: 12px">就像上面这样,然后我发现,无论我怎么点,都不会触发这个方法了,再细心点,就发现,在渲染的时候,就调用了一次,而且仅此一次,再也不能调用了.</span></div>
<div><br><span style="font-size: 12px">
原因是jsx语法,渲染的时候会把{}里面包裹的代码先解析一遍,因为如果加了括号,直接就执行了里面的函数,就没有东西了,但是这个时候,this是可以拿到的</span></div>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">class App extends Component {
handleClick(){
      console.log(this); //下面调用加了(),这个时候发现,this是可以拿到的
}
render() {
    return (
      &lt;div className="App"&gt;
      &lt;button onClick={this.handleClick()}&gt;点我&lt;/button&gt; //这里加了括号的
      &lt;/div&gt;
    );
}
}
</pre>
</div>
<p><span style="font-size: 18px"><strong>  好像问题越来越明朗了,为啥会拿不到,和class没有关系,完全是因为react自己封装的东西,先会把{}里面的代码解析一遍,于是大概就是下面这种情况了</strong></span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">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(() =&gt; { obj.handleClick() }));// () =&gt; { obj.handleClick() } react对{}的解析
    (eval(() =&gt; {obj.handleClick()}))() //onclick触发点击事件 这里输出this还是obj,所以this就保留了
</pre>
</div>
<h3><span style="font-size: 18pt">  所以问题出在react对{}的解析会把this的指向解除了</span></h3>
</div>
</div>
</div><br><br>
来源:https://www.cnblogs.com/zhaohongcheng/p/11235679.html
頁: [1]
查看完整版本: react的事件处理为什么要bind this 改变this的指向?