reactjs中的bind问题

import React,{Component} from 'react';

class Search extends Component{
    constructor(props){
        super(props);
        this.state = {name:''};
    }

    handleSearch(){
        console.log(this); // null
        console.log(this.state.name);// 报错
    }

    render(){
        return (
            <div>
                <input type="text" value={this.state.value}/>
                <button onClick={this.handleSearch}>搜搜</button>
            </div>
        );
    }
}

请问代码中的打印log那里的this为什么是null?handleSearch是button中调用的,怎么也不可能是null啊?应该是button这个dom吧。

另外,在页面中直接这样写:

var handleClick =  function (event) {
    console.log(this);    // 不是null是<div id="foo"></div>
}
document.getElementById('foo').addEventListener('click', handleClick);
document.getElementById('foo').click();

我知道怎么解决。我只想知道react中this为什么不是dom而是null??

阅读 4.8k
6 个回答

更新

原来楼主问的是为什么thisnull,而不是DOM或者window之类的东西。。。嗯,我也很好奇,所以我查了一下源码,跳来跳去好晕。。。

先说一下,按照你的写法,在development环境下,是null。在production环境下,是undefined

简单的说一下原因:

  1. babel编译出来的代码都会添加"use strict",变成严格模式。而你知道,如果使用严格模式,而没有手动绑定this的话,那么this不是window,而是undefined。而如果使用bind(null)的话,this就是null

  2. 然后,由于react使用的是事件代理,并不是原生的事件,所以他的调用方法并不会像原生那样绑定对象的DOM

  3. 最后,经过源码的观察来看,事件的callback在存入的时候,并没有做任何绑定。在调用的时候,在production下,没有做什么绑定。而在development下,绑定了null。(或者这么说不准确,事件的回调在添加的时候,使用proxyMethod做了一层封装,而在里面是用了apply(this, arguments)来调用原来的回调函数。而在production下,没有对proxyMethod做什么绑定,所以上面apply时候的thisundefined。而在development下,绑定了null,所以上面的thisnull

不知道你明白没。。。

原答案

四种解决方法,任何一种都可以解决

  • 像@hyy1115那样在constructor里面绑定一下

  • <button onClick={this.handleSearch.bind(this)}>搜搜</button>绑定

  • 这个样子调用:<button onClick={()=>{ this.handleSearch()}}>搜搜</button>

  • 使用箭头函数可以解决这个问题

  handleSearch = ()=>{
        console.log(this); // null
        console.log(this.state.name);// 报错
    }

React开发组在决定实现组件对ES6类的支持时取消了自动绑定,具体可以看这里

动动手指绑定一下

import React,{Component} from 'react';

class Search extends Component{
    constructor(props){
        super(props);
        this.state = {name:''};
        this.handleSearch = this.handleSearch.bind(this)
    }

}

因为你这是jsx语法写的,实际上最终编译出来的可是 :

    React.createElement('button',{onClick : this.handleSearch},'搜搜')

由此可见这个事件函数只是引用了当前指针,但是这个click函数运行的上下文环境并不在这个Search组件内部,所以js引擎找不到this,最终会出错,解决方法都很完善,就不多嘴了

使用createClass 方式创建的组件的 函数式自动绑定的
使用es6 则需要手动绑定

  1. 在constructor中 clickHandler= this.clickHandler.bind(this)

  2. 箭头函数

  3. es7双冒号绑定 在组件中 onClick = {::this.clickHandler}

你说的第二种通过addEventListener绑定事件的方法是原生事件绑定,和第一种不一样,第一种是React的三种合成事件绑定的一种,使用合成事件绑定的一个点就是要手动绑定,绑定方式上述回答已经说的很详细了。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题