在react jsx中,爲何使用箭頭函數和bind容易出現問題

在以前的文章中,已經說明如何避免在react jsx中使用箭頭函數和bind(https://medium.freecodecamp.o... 可是沒有提供一個清晰的demo展現爲何要這樣作。html

如今來一些例子吧。react

在這個例子中,咱們經過使用一個箭頭函數(=>)來bind用戶ID到每一個刪除按鈕中。git

## 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結果。我已經定義UserPureComponent。因此只有當props或者state修改時纔會從新渲染User。可是當你點擊刪除的時候,發現render在全部User實例中觸發了。github

怎麼會這個樣子?由於()=>this.deleteUser(user.id)每執行一次就會生成一個新的函數,固然bind也是這樣乾的,因此在PureComponent的shallowCompare中認爲onDeleteClick的值已經被修改,因此觸發了從新渲染。看吧,使用箭頭函數和bind會形成性能浪費,做爲一個節約的程序員應該避免如此。api

那咱們應該怎樣作呢?

請看下面的代碼閉包

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傳遞下去了。dom

相關文章
相關標籤/搜索