在react jsx中,為什麼使用箭頭函式和bind容易出現問題
阿新 • • 發佈:2018-12-22
在之前的文章中,已經說明如何避免在react jsx中使用箭頭函式和bind(https://medium.freecodecamp.o... 但是沒有提供一個清晰的demo展示為什麼要這樣做。
現在來一些例子吧。
在這個例子中,我們通過使用一個箭頭函式(=>)來bind使用者ID到每個刪除按鈕中。
## index.js import React from 'react'; import { render } from 'react-dom'; import User from './User'; class App extends React.Component { constructor(props) { super(props); this.state = { users: [ { id: 1, name: 'Cory' }, { id: 2, name: 'Meg' }, { id: 3, name: 'Bob' } ] }; } deleteUser = id => { this.setState(prevState => { return { users: prevState.users.filter( user => user.id !== id) } }) } render() { return ( <div> <h1>Users</h1> <ul> { this.state.users.map( user => { return <User key={user.id} name={user.name} onDeleteClick={() => this.deleteUser(user.id)} /> }) } </ul> </div> ); } } export default App; render(<App />, document.getElementById('root'));
在onDeleteClick={() => this.deleteUser(user.id)}
這一行中,我們使用一個箭頭函式來傳遞value到deleteUser 函式中。這就是問題所在了。
## User.js import React from 'react'; // Note how the debugger below gets hit when *any* delete // button is clicked. Why? Because the parent component // uses an arrow function, which means this component // class User extends React.PureComponent { render() { const {name, onDeleteClick } = this.props console.log(`${name} just rendered`); return ( <li> <input type="button" value="Delete" onClick={onDeleteClick} /> {name} </li> ); } } export default User;
看一看User.js檔案。每當我登入的時候控制檯都會打印出渲染執行時的console結果。我已經定義User
為PureComponent。所以只有當props或者state修改時才會重新渲染User
。但是當你點選刪除的時候,發現render在所有User例項中觸發了。
怎麼會這個樣子?因為()=>this.deleteUser(user.id)
每執行一次就會生成一個新的函式,當然bind也是這樣乾的,所以在PureComponent的shallowCompare中認為onDeleteClick的值已經被修改,所以觸發了重新渲染。看吧,使用箭頭函式和bind會造成效能浪費,作為一個節約的程式設計師應該避免如此。
那我們應該怎樣做呢?
請看下面的程式碼
import React from 'react';
import { render } from 'react-dom';
import User from './User';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
users: [
{ id: 1, name: 'Cory' },
{ id: 2, name: 'Meg' },
{ id: 3, name: 'Bob'}
],
};
}
deleteUser = id => {
this.setState(prevState => {
return {
users: prevState.users.filter(user => user.id !== id)
};
});
};
renderUser = user => {
return <User key={user.id} user={user} onClick={this.deleteUser} />;
}
render() {
return (
<div>
<h1>Users</h1>
<ul>
{this.state.users.map(this.renderUser)}
</ul>
</div>
);
}
}
render(<App />, document.getElementById('root'));
上面的例子就沒有箭頭函數了。這裡面使用了閉包的概念,把user傳遞下去了。