我现在学习React,并且注意到很多人将其方法绑定到构造函数中。
赞:
class MyComponent extends React.Component {
constructor() {
super();
this.myMethod = this.myMethod.bind(this);
}
render() {
<button onClick={this.myMethod}>Click me</button>
}
myMethod() {
// do something
}
}
但是我习惯于写这样的东西:
render() {
<button onClick={this.myMethod.bind(this)}>Click me</button>
}
几个人告诉我,使用第二种方法是不好的体验。
那么您能告诉我第一方法和第二方法之间的区别吗?任何利弊?或性能问题?
答案 0 :(得分:1)
你是对的,别人告诉你的也是对的。
我们鼓励您在构造函数中进行绑定,因为每个组件只对构造函数进行一次调用,因此,如果在构造函数中进行绑定,则它只会在Webpack bundle.js文件中创建一次新的对象/函数,因此影响不大
不建议您直接在render中进行绑定,因为组件会出于多种原因进行渲染,例如执行setState时,组件收到新的props时,因此组件将渲染很多次。因此,由于您每次在组件渲染时都直接绑定在render中,因此每次在Webpack bundle.js中都会创建一个新函数,并且捆绑文件的大小会增加,并且当您的应用程序包含数千个组件并且如果您直接在其中绑定时,这会影响性能。在每个组件中渲染。
因此,建议您仅在构造函数中进行绑定。希望能澄清
答案 1 :(得分:1)
您应该仅在构造函数中进行绑定,因为第二种方法将在每次渲染时创建一个新函数。
但是有一种更好的方法来避免绑定。使用箭头功能。
class MyComponent extends React.Component {
constructor() {
super();
}
render() {
<button onClick={this.myMethod}>Click me</button>
}
myMethod = ()=> {
// do something
}
}
让我们看看Redux Dan Abramov thinks about bind vs arrow functions-的创建者
在性能方面,使用箭头之间有什么区别 功能和使用es6类时手动绑定?使用箭头 函数的方法不在类原型上,它将在 仅类实例。使用bind将方法附加到类上 原型。听起来像手动绑定将具有更好的性能, 这是否意味着我们应该考虑使用bind而不是arrow 类方法的功能?
任何建议或评论都非常感谢!
因此,在性能方面,您是否建议使用
class MyComponent扩展了React.Component {构造函数(props){ 超级(道具)}
methodA =()=> {...}}
或
class MyComponent扩展了React.Component {构造函数(props){ 超级(道具) this.methodA = this.methodA.bind(this)}
methodA(){...}}
这两种编写方式是等效的。 (第二个是 编译为第一个。)
使用bind将方法附加到类原型上。
在您的示例中,您仍然将函数附加到实例:
this.methodA = this.methodA.bind(this)
所以它们本质上是相同的。
在Facebook,我们使用第二种方式(“类属性”),但请注意 这仍然是实验性的,不是ES6的一部分。如果你只想 坚持使用稳定的语法,那么您可以手动绑定它们。
答案 2 :(得分:1)
这将导致在每个render
调用上创建一个新的绑定函数:
render() {
<button onClick={this.myMethod.bind(this)}>Click me</button>
}
请注意,如果在多个位置使用myMethod
,则需要多次bind
调用,并且如果缺少bind
之一,可能会导致未绑定的回调。
这会在组件实例化时创建绑定函数:
constructor() {
super();
this.myMethod = this.myMethod.bind(this);
}
推荐第二个选项。
像autobind
这样的装饰器可以用来跳过myMethod
在构造器中的显式分配。
如this answer中所述,具有bind
的原型方法比箭头实例方法具有更少的缺点,并且通常是首选。
答案 3 :(得分:0)
我从eslint-plugin-react文档中获取了此信息:
JSX prop中的绑定调用或箭头函数将在每个渲染器上创建一个全新的函数。这对性能不利,因为这将导致以不必要的方式调用垃圾回收器。如果将新功能作为道具传递给组件,而该组件使用该道具上的引用相等性检查来确定是否应更新,则也可能导致不必要的重新渲染。
作为我的补充说明,在JSX中使用this
也会引起混淆。我鼓励您阅读以下文档:https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md
答案 4 :(得分:0)
您应避免使用箭头功能并在渲染中进行绑定。破坏性能 诸如shouldComponentUpdate和PureComponent之类的优化。
有关出色的阅读和演示,您可能希望参考 this.
答案 5 :(得分:0)
第一种方法是正确的性能明智的选择,因为在每个渲染器上,此onClick
道具将指向同一对象,而在第二个示例中并非如此。
如果看下面的示例,当我增加计数器时,将看到MyPureCompOne
不会渲染,但是MyPureCompTwo
会渲染。因为每次<App>
组件呈现时,MyPureCompTwo
道具handleClick
都被分配了一个新的函数对象,这就是为什么作为纯组件的props浅浅比较是错误的,并且会呈现。不需要此渲染。但是MyPureCompOne
的情况并非如此,因为每次App
渲染时,handleClick
道具仍指向相同的函数对象(this.handleClickOne
),该对象是在App
首次安装。
class MyPureCompOne extends React.PureComponent {
render() {
console.log("rendring component one");
return <button onClick={this.props.handleClick}>First Button</button>
}
}
class MyPureCompTwo extends React.PureComponent {
render() {
console.log("rendring component two");
return <button onClick={this.props.handleClick}>Second Button</button>;
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
this.handleCountChange = this.handleCountChange.bind(this);
this.handleClickOne = this.handleClickOne.bind(this);
}
handleCountChange() {
this.setState(prevState => ({
count: prevState.count + 1
}));
}
handleClickOne(e) {
console.log("Clicked..");
}
handleClickTwo() {
console.log("Clicked..");
}
render() {
const { count } = this.state;
return (
<div>
<button onClick={this.handleCountChange}>Change Counter</button>
<MyPureCompOne handleClick={this.handleClickOne} />;
<MyPureCompTwo handleClick={this.handleClickTwo.bind(this)} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id='root'></div>