React 组件中处理 onClick 类似事件绑定的时候,是需要显式给处理器绑定上下文(context)的,这一度使代码变得冗余和难看。
请看如下的示例: class App extends Component { constructor() { super(); this.state = { isChecked: false }; } render() { return ( <div className="App"> <label > check me: <input type="checkbox" checked={this.state.isChecked} onChange={this.toggleCheck} /> </label> </div> ); } toggleCheck() { this.setState(currentState => { return { isChecked: !currentState.isChecked }; }); } } 页面上放了一个 事件处理器上下文丢失的报错 因为 调试查看丢失上下文后 出乎意料,是 WHY当然这并不是 React 的锅,这是 JavaScript 中 默认的绑定function display(){ console.log(this) } display() // 严格模式下为全局 `window`,非严格模式下为 `undefined` 隐式绑定通过对象来调用,该函数的上下文被隐式地指定为该对象。 var obj = { name: ‘Nobody‘, display: function(){ console.log(this.name); } }; obj.display(); // Nobody. 里面取的是 obj 身上的 `name` 属性 但,如果把该对象上的方法赋值给其他变量,或通过参数传递的形式,再执行,那光景就又不一样了。 var obj = { name: "Nobody", display: function() { console.log(this.name); } }; var name = "global!"; var outerDisplay = obj.display; outerDisplay(); // global! 这里取到的 `name` 是全局中的内个 这里赋值给 function invoker(fn) { fn(); } setTimeout( obj.display, 1000 ); // global! invoker(obj.display); // global! 这里 强制绑定这个时候, var name = “global!”; obj.display = obj.display.bind(obj); var outerDisplay = obj.display; outerDisplay(); // Nobody
现场还原有了上面的背景,就可以还原文章开头的问题了,即事件处理器的上下文 丢失的问题。 JSX 中的 HTML 标签本质上对应 React 中创建该标签的一个函数。比如你写的 React.createElement( type, [props], [...children] ) 标签上的属性会作为
React.createElement(type, props){ // 让我们创建一个 <type> 并在 <type> 的值发生变化的时候调用一下 `props.onChange` ... props.onChange() // 它已经不是原来的方法了,丢失了上下文 ... } 因为 ES6 的 Class 是在严格模式下执行的,所以事件处理器中如果使用了 所以你看到 React 官方的示例中,constructor 里有 constructor() { super(); this.state = { isChecked: false }; + this.toggleCheck = this.toggleCheck.bind(this); } 这样是能正常工作了,但是,这句代码的存在真的很别扭,因为,
避免的方式有很多,就看哪种最对味。下面来看看如何避免写这些绑定方法。 #0行内的绑定最简单的可以在行内进行绑定操作,这样不用单独写一句出来。 <input type="checkbox" checked={this.state.isChecked} - onChange={this.toggleCheck} + onChange={this.toggleCheck.bind(this)} /> #1箭头函数因为箭头函数不会创建新的作用域,其上下文是语义上的(lexically)上下文。所以在绑定事件处理器时,直接使用剪头函数是很方便的一种规避方法。 <input type="checkbox" checked={this.state.isChecked} - onChange={this.toggleCheck} + onChange={() => this.toggleCheck()} /> #2将类的方法改成属性如果将这个处理器作为该组件的一个属性,这个属性作为事件的处理器以箭头函数的形式存在,执行的时候也是能正常获取到上下文的。 - toggleCheck() { + toggleCheck = () => { this.setState(currentState => { return { isChecked: !currentState.isChecked }; }); } 总结React 组件中,其实跟 React 没多大关系,传递事件处理器,或方法作为回调时,其上下文会丢失。为了修复,我们需要显式地给这个方法绑定一下上下文。除了常用的在构造器中进行外,还可通过箭头函数,公有属性等方式来避免冗余的绑定语句。 相关资源 |
原文地址:https://www.cnblogs.com/Wayou/p/get_rid_of_bind_within_react_component.html