为何React组件中一处无需bind()可运行,另一处却必须绑定?
为什么React组件中箭头函数能自动捕获this,普通方法却需要bind?
我有两个React组件:
- Clock组件在
componentDidMount中用箭头函数调用tick()方法,没用到bind()也能正常运行; - Toggle组件的
handleClick方法如果不通过bind()绑定this就无法工作。
想搞懂为什么前者能自动捕获this?
Clock组件代码
class Clock extends React.Component { constructor(props){ super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(),1000); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div style={{border:"1px solid black"}}> <h1 style={{color:"blue"}}> Component Clock has been rendered </h1> <h2> Time: {this.state.date.toLocaleTimeString()}</h2> </div> ); } };
Toggle组件代码
class Toggle extends React.Component { constructor(props) { super(props); this.state = {isToggleOn: true}; 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> ); } }
核心原因:箭头函数和普通函数的this绑定规则不一样
1. Clock组件里的箭头函数为什么能正确拿到this?
箭头函数的this是词法绑定的——它不会自己创建新的this,而是直接继承当前所在作用域的this。
在componentDidMount方法里,这个方法本身是组件实例的方法,所以这里的this指向Clock组件的实例。传给setInterval的箭头函数() => this.tick()会直接捕获这个this,调用this.tick()时,this依然指向组件实例,自然能正常调用setState。
2. Toggle组件的普通方法为什么需要bind?
handleClick是普通的类方法,类方法的this默认是动态绑定的——谁调用它,this就指向谁。
当你把this.handleClick传给按钮的onClick时,只是传递了方法的引用。按钮被点击时,是浏览器事件系统调用这个方法,此时调用者不是组件实例,this会丢失(严格模式下为undefined),自然找不到this.setState。
所以必须在构造函数里用this.handleClick = this.handleClick.bind(this),把方法的this强制绑定到组件实例上,这样不管谁调用它,this都指向组件实例。
补充:其他不用bind的写法
除了构造函数bind,还有两种常用方式可以避免手动绑定:
- 用箭头函数定义类方法(ES6+支持):
handleClick = () => { this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })); } - 在render里用箭头函数包裹:
<button onClick={() => this.handleClick()}> {this.state.isToggleOn ? 'On' : 'Off'} </button>
不过第二种写法每次render都会创建新的箭头函数,性能敏感场景需要注意。
内容的提问来源于stack exchange,提问作者Boris Borais
相关产品推荐
相关产品推荐

