1. 程式人生 > >在react jsx中,為什麼使用箭頭函式和bind容易出現問題

在react jsx中,為什麼使用箭頭函式和bind容易出現問題

在之前的文章中,已經說明如何避免在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結果。我已經定義UserPureComponent。所以只有當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傳遞下去了。

來源:https://segmentfault.com/a/1190000011007769