在react
中创建组件的时候, 如果有用到回调方法传递到下级组件, 而在方法中需要使用this
参数时候, 有两种方法可以使用, 一种是使用bind
方法绑定this
, 还一种是使用箭头函数绑定this
. 一般推荐都是使用bind
方法, 因为箭头函数在每次执行render
方法时都会重新生成一次, 造成传入的props
改变, 重新触发render
.
1 2 3 4 5
| 1. this.childChange = this.childChange.bind(this); <Child onChange={this.childChange}/> 2. <Child onChange={(event)=>{this.childChange(event)}}/>
|
在第 2 种写法中, 当Child
组件是PureComponent
时, 也会在每次父组件执行render
之后执行render
, 因为props.onChange
属性改变了.
那么, 一般在需要传入回调函数时候, 都使用bind
之后的函数就可以了, 但是在某些特殊情况下, 必须要使用箭头函数时, 如何优化呢.
1 2 3 4 5 6 7 8 9 10 11
| childChange(event, index){ ...; } <NgFor for={arraysItem} of="item" render={ function (_props) { return (<Child onChange={(event)=>{this.childChange(event, _props.$$index)} />) }}> </NgFor> {arrays.map((value, index) => { return (<Child onChange={(event)=>{this.childChange(event, index)} />) })}
|
当使用闭包传入值的时候, 即使执行bind
后的方法, 也需要在里面使用箭头函数调用, 传入index
值. 那么需要用到bind
函数的args
来优化.
自定义一个bindOnce
方法, 传入组件和要绑定的方法以及其他参数, 对方法进行bind
和缓存.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import Immutable from 'immutable';
var __bindOnce = function (component, func, ...args) { if (!component.__bindFuncs) { component.__bindFuncs = Immutable.Map(); } let __bindFuncs = component.__bindFuncs; let argsMap = Immutable.fromJS(args); if (__bindFuncs.has(func)) { if (__bindFuncs.get(func).has(argsMap)) { return __bindFuncs.get(func).get(argsMap); } else { let bindFunc = func.bind(component, ...args); component.__bindFuncs = __bindFuncs.update(func, (v) => v.set(argsMap, bindFunc)); return bindFunc; } } else { let bindFunc = func.bind(component, ...args); component.__bindFuncs = __bindFuncs.set(func, Immutable.Map().set(argsMap, bindFunc)); return bindFunc; } };
export default bindOnce;
|
这里使用了immutable
的Map
来作为缓存字典, 因为Map
结构可以使用Object
和function
作为Key
. 使用方法:
1 2 3 4 5 6 7 8 9 10 11
| childChange(index, event){ ...; } <NgFor for={arraysItem} of="item" render={ function (_props) { return (<Child onChange={bindOnce(this, this.childChange, _props.$$index)} />) }}> </NgFor> {arrays.map((value, index) => { return (<Child onChange={bindOnce(this, this.childChange, index)} />) })}
|
可以见到, 唯一需要改变的就是, 在childChange
中, event
参数的位置在最后, 这是因为onChange
总会传入event
参数, 而先bind
的参数会出现在参数列表前面. 当使用了bindOnce
之后, Child
便不会因为props
中onChange
变化而重新render
了.