如何避免在渲染方法中绑定或内联箭头函数 [英] How to avoid bind or inline arrow functions inside render method
问题描述
我们应该避免在 render 内部绑定方法,因为在重新渲染时它会创建新方法而不是使用旧方法,这会影响性能.
对于这样的场景:
我们可以在构造函数中绑定_handleChange
方法:
this._handleChange = this._handleChange.bind(this);
或者我们可以使用属性初始化语法:
_handleChange = () =>{....}
现在让我们考虑我们想要传递一些额外参数的情况,假设在一个简单的待办事项应用程序中,点击项目我需要从数组中删除项目,为此我需要传递项目索引或待办事项每个 onClick 方法中的名称:
todos.map(el => {el} )
现在假设 todo 名称是唯一的.
根据DOC:
<块引用>这种语法的问题是创建了不同的回调每次组件渲染时.
问题:
如何在render方法中避免这种绑定方式或者有什么替代方法?
请提供任何参考或示例,谢谢.
首先: 一个简单的解决方案是为 map 函数内的内容创建一个组件,并将值作为 props 和何时传递您从子组件调用函数,您可以将值传递给作为道具传递的函数.
父母
deleteTodo = (val) =>{控制台日志(val)}todos.map(el =><MyComponent val={el} onClick={this.deleteTodo}/>)
我的组件
class MyComponent 扩展 React.Component {deleteTodo = () =>{this.props.onClick(this.props.val);}使成为() {return {this.props.val} </div>}}示例代码段
class Parent extends React.Component {_deleteTodo = (val) =>{控制台日志(val)}使成为() {var todos = ['a', 'b', 'c'];返回 (<div>{todos.map(el =><MyComponent key={el} val={el} onClick={this._deleteTodo}/>)}
)}}class MyComponent 扩展了 React.Component {_deleteTodo = () =>{console.log('这里');this.props.onClick(this.props.val);}使成为() {return
{this.props.val} </div>}}ReactDOM.render( , document.getElementById('app'));<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="app"></div>
第二:另一种方法是使用 memoize 并返回一个函数
constructor() {极好的();this._deleteTodoListener = _.memoize(this._deleteTodo, (元素) =>{返回 element.hashCode();})}_deleteTodo = (元素) =>{//这里删除处理}
并像使用它一样
todos.map(el => {el} )
<块引用>
附言然而,这不是最好的解决方案,仍然会导致正在创建多个功能,但仍然比初始案例.
第三:然而,更合适的解决方案是将 attribute
添加到最顶层的 div 并从 event
中获取值,例如
_deleteTodo = (e) =>{console.log(e.currentTarget.getAttribute('data-value'));}todos.map(el => <div key={el} data-value={el} onClick={this._deleteTodo}> {el} </div>)
但是,在这种情况下,使用 toString 方法将属性转换为字符串,因此对象将转换为 [Object Object]
和数组,如 ["1" , "2", "3"]
为 "1, 2, 3"
We should avoid method binding inside render because during re-rendering it will create the new methods instead of using the old one, that will affect the performance.
So for the scenarios like this:
<input onChange = { this._handleChange.bind(this) } ...../>
We can bind _handleChange
method either in constructor:
this._handleChange = this._handleChange.bind(this);
Or we can use property initializer syntax:
_handleChange = () => {....}
Now lets consider the case where we want to pass some extra parameter, lets say in a simple todo app, onclick of item i need to delete the item from array, for that i need to pass either the item index or the todo name in each onClick method:
todos.map(el => <div key={el} onClick={this._deleteTodo.bind(this, el)}> {el} </div>)
For now just assume that todo names are unique.
As per DOC:
The problem with this syntax is that a different callback is created
each time the component renders.
Question:
How to avoid this way of binding inside render method or what are the alternatives of this?
Kindly provide any reference or example, thanks.
解决方案 First: A simple solution will be to create a component for the content inside a map function and pass the values as props and when you call the function from the child component you can pass the value to the function passed down as props.
Parent
deleteTodo = (val) => {
console.log(val)
}
todos.map(el =>
<MyComponent val={el} onClick={this.deleteTodo}/>
)
MyComponent
class MyComponent extends React.Component {
deleteTodo = () => {
this.props.onClick(this.props.val);
}
render() {
return <div onClick={this.deleteTodo}> {this.props.val} </div>
}
}
Sample snippet
class Parent extends React.Component {
_deleteTodo = (val) => {
console.log(val)
}
render() {
var todos = ['a', 'b', 'c'];
return (
<div>{todos.map(el =>
<MyComponent key={el} val={el} onClick={this._deleteTodo}/>
)}</div>
)
}
}
class MyComponent extends React.Component {
_deleteTodo = () => {
console.log('here'); this.props.onClick(this.props.val);
}
render() {
return <div onClick={this._deleteTodo}> {this.props.val} </div>
}
}
ReactDOM.render(<Parent/>, document.getElementById('app'));
<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="app"></div>
EDIT:
Second: The other approach to it would be to use memoize and return a function
constructor() {
super();
this._deleteTodoListener = _.memoize(
this._deleteTodo, (element) => {
return element.hashCode();
}
)
}
_deleteTodo = (element) => {
//delete handling here
}
and using it like
todos.map(el => <div key={el} onClick={this._deleteTodoListener(el)}> {el} </div>)
P.S. However this is not a best solution and will still result in
multiple functions being created but is still an improvement over the
initial case.
Third: However a more appropriate solution to this will be to add an attribute
to the topmost div and get the value from event
like
_deleteTodo = (e) => {
console.log(e.currentTarget.getAttribute('data-value'));
}
todos.map(el => <div key={el} data-value={el} onClick={this._deleteTodo}> {el} </div>)
However, in this case the attributes are converted to string using toString method and hence and object will be converted to [Object Object]
and and array like ["1" , "2", "3"]
as "1, 2, 3"
这篇关于如何避免在渲染方法中绑定或内联箭头函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文