128 votes

Pourquoi ne pas JSX accessoires de flèche de fonctions ou de se lier?

Je suis en cours d'exécution de la charpie avec mon Réagir application, et je reçois cette erreur:

error    JSX props should not use arrow functions        react/jsx-no-bind

Et c'est là que je suis sur la flèche de la fonction (à l'intérieur d' onClick):

{this.state.photos.map(tile => (
  <span key={tile.img}>
    <Checkbox
      defaultChecked={tile.checked}
      onCheck={() => this.selectPicture(tile)}
      style={{position: 'absolute', zIndex: 99, padding: 5, backgroundColor: 'rgba(255, 255, 255, 0.72)'}}
    />
    <GridTile
      title={tile.title}
      subtitle={<span>by <b>{tile.author}</b></span>}
      actionIcon={<IconButton onClick={() => this.handleDelete(tile)}><Delete color="white"/></IconButton>}
    >
      <img onClick={() => this.handleOpen(tile.img)} src={tile.img} style={{cursor: 'pointer'}}/>
    </GridTile>
  </span>
))}

Est-ce une mauvaise pratique qui devrait être évité? Et quelle est la meilleure façon de le faire?

199voto

Ori Drori Points 65611

Pourquoi vous ne devriez pas utiliser inline flèche fonctions dans JSX accessoires

À l'aide de la flèche de fonctions ou de liaison dans JSX est une mauvaise pratique qui nuit à la performance, parce que la fonction est recréé à chaque rendu.

  1. Chaque fois qu'une fonction est créée, la fonction précédente est des ordures collectées. Nouveau rendu de nombreux éléments pourraient créer jank dans les animations.

  2. À l'aide d'un inline flèche en fonction de la cause PureComponents, et les composants qui utilisent shallowCompare dans la shouldComponentUpdate méthode alors rendre à nouveau de toute façon. Depuis la flèche de la fonction prop est recréée à chaque fois, les eaux peu profondes à comparer l'identifier comme un changement à une béquille, et le composant rerender.

Comme vous pouvez le voir dans les 2 exemples suivants - lorsque nous utilisons inline flèche de la fonction, l' <Button> composant est réaffichées à chaque fois (la console affiche le 'bouton de rendu de texte).

Exemple 1 - PureComponent sans inline gestionnaire

class Button extends React.PureComponent {
  render() {
    const { onClick } = this.props;
    
    console.log('render button');
    
    return (
      <button onClick={ onClick }>Click</button>
    );
  }
}

class Parent extends React.Component {
  state = {
    counter: 0
  }
  
  onClick = () => this.setState((prevState) => ({
    counter: prevState.counter + 1
  }));
  
  render() {
    const { counter } = this.state;
    
    return (
      <div>
        <Button onClick={ this.onClick } />
        <div>{ counter }</div>
      </div>
    );
  }
}

ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<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>

Exemple 2 - PureComponent avec inline gestionnaire

class Button extends React.PureComponent {
  render() {
    const { onClick } = this.props;
    
    console.log('render button');
    
    return (
      <button onClick={ onClick }>Click</button>
    );
  }
}

class Parent extends React.Component {
  state = {
    counter: 0
  }
  
  render() {
    const { counter } = this.state;
    
    return (
      <div>
        <Button onClick={ () => this.setState((prevState) => ({
          counter: prevState.counter + 1
        })) } />
        <div>{ counter }</div>
      </div>
    );
  }
}

ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<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>

Méthodes de reliure d' this sans inline fonctions de flèche

  1. La liaison de la méthode manuellement dans le constructeur:

    class Button extends React.Component {
      constructor(props, context) {
        super(props, context);
    
        this.cb = this.cb.bind(this);
      }
    
      cb() {
    
      }
    
      render() {
        return (
          <button onClick={ this.cb }>Click</button>
        );
      }
    }
    
  2. La liaison d'une méthode à l'aide de la proposition de la classe-les champs avec une flèche de la fonction. Comme c'est une étape 3 de la proposition, vous devez ajouter l' Étape 3 preset ou les propriétés de la Classe transformer à votre babel de configuration.

    class Button extends React.Component {
      cb = () => { // the class property is initialized with an arrow function that binds this to the class
    
      }
    
      render() {
        return (
          <button onClick={ this.cb }>Click</button>
        );
      }
    }
    

9voto

C'est parce que une flèche fonction, apparemment, va créer une nouvelle instance de la fonction sur chaque rendu si utilisé dans un JSX de la propriété. Cela peut créer une énorme pression sur le garbage collector et empêchera le navigateur à partir d'optimiser tout chaud "chemins" étant donné que les fonctions seront jetées au lieu de les réutiliser.

Vous pouvez voir l'ensemble de l'explication et de quelques infos à https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md

4voto

supNate Points 42

Pour éviter de créer de nouvelles fonctions avec les mêmes arguments, vous pourriez memoize la fonction bind résultat, ici, c'est un simple utilitaire nommé memobind le faire: https://github.com/supnate/memobind

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X