假设您有以下TSX代码:
render() {
const someParameter = 5;
return (
<div onClick={() => this.doSomething(someParameter)}></div>
);
}
现在,我们知道我们不应该像这样将胖箭头函数传递给onClick处理程序,因为它每次都会创建一个新函数,强制重新呈现(这在以下情况下特别糟糕)我们将此回调传递给深层组件,而不仅仅是div。)
那么解决方案,如果没有参数,将在我们类的构造函数中绑定doSomething
到this
,如this.doSomething = this.doSomething.bind(this)
,然后将绑定函数作为打回来。但是,在我们的情况下,这并没有削减它,因为我们想要将参数传递给函数 - someParameter。想象一下,someParameter并不像上面那样只是一个愚蠢的常量,而是一个数组中的元素,我们在render方法中的数组中得到map()。我们如何处理这种情况?也就是说,我们如何传递一个不是每次都从头创建的函数,从而打破了我们只在必要时才能巧妙地重新渲染的能力?
谢谢!
答案 0 :(得分:2)
bind
不仅可以绑定上下文,还可以绑定参数。所以你可以在构造函数中做这样的事情:
this.doSomething = this.doSomething.bind(this, someArgument)
只有在组件生命周期内someArgument
没有发生变化时,上述解决方案才有效
如果这个参数是动态的,唯一的解决方案是使用像你的例子中的箭头函数 - 但是请注意,只有当这个函数作为prop组件传递给子组件(而不是HTML元素)时,才会产生额外的重新渲染。反应文件:
在大多数情况下,这很好。但是,如果此回调作为a传递 支持降低组件,这些组件可能会做额外的 重新渲染。
如果你没有将它传递给React子组件,它应该不是问题,不会导致任何额外的重新渲染。请注意,React组件和HTML标记之间存在差异。如果你使用箭头函数作为HTML元素的事件回调(例如,在map中生成的div),它将不会触发此div
的额外渲染,因为它不是一个组件而且没有渲染方法。 React Virtual DOM算法将决定是否应更新与此div
对应的实际DOM元素,在我们的情况下,现有DOM元素将不会更新(您可以使用开发工具进行检查)。
class Hello extends React.Component{
constructor() {
super();
this.state = {test: 0};
}
componentDidMount() {
var i =0;
this.timer = setInterval(() => {
i++;
this.setState({test: i})
}, 1000)
}
componentWillUnmount() {
clearInterval(this.timer)
}
render() {
return (<div>{this.state.test}
{
[1, 4, 6].map((v) => {
return (<div key={v} onClick={() => { console.log(this.state.test)}}>test</div>)
})
}
</div>);
}
};
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
您可以检查上面的代码段生成的outoput,看看div
元素在DOM中没有更新,尽管它们的箭头函数定义为事件回调,而父组件则重新生成。
如果你需要将这个函数传递给子组件,你可以选择使用带有参数值的函数和prop来传递prop,以避免极端重新渲染(当然你还需要实现shouldComponentUpdate
):
<SomeComponent myClick={this.doSomething} myArgument={someArgument} />
和SomeComponent中的某个地方:
//JSX in SomeComponent render method
<div onClick={() => this.props.myClick(this.props.myArgument)} >...</div>
您还可以在SomeComponent中创建其他方法,而不是使用箭头函数:
handleMyClick() {
this.props.myClick(this.props.myArgument);
}
然后使用它JSX:
<div onClick={this.handleMyClick} >...</div>
总而言之:如果你使用箭头函数作为HTML标签上的事件回调,它不应该导致性能问题,也不会触发任何额外的重新渲染 - 它不会破坏仅在必要时巧妙地重新渲染的能力。只有当箭头功能作为支撑传递给子组件时,它才可能导致额外的重新渲染,在这种情况下,您可以使用我建议的洗脱剂。
答案 1 :(得分:0)
请您检查一下这里提出的解决方案&#34; Protips&#34;部分? https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md
看起来好像这可行:
var List = createReactClass({
render() {
return (
<ul>
{this.props.items.map(item =>
<ListItem key={item.id} item={item} onItemClick={this.props.onItemClick} />
)}
</ul>
);
}
});
var ListItem = createReactClass({
render() {
return (
<li onClick={this._onClick}>
...
</li>
);
},
_onClick() {
this.props.onItemClick(this.props.item.id);
}
});