Quel est le '@' (symbole at) dans le décorateur Redux @connect?

226

J'apprends Redux avec React et suis tombé sur ce code. Je ne sais pas s'il est spécifique à Redux ou non, mais j'ai vu l'extrait de code suivant dans l'un des exemples.

@connect((state) => {
  return {
    key: state.a.b
  };
})

Bien que la fonctionnalité de connectsoit assez simple, mais je ne comprends pas ce qui @précède connect. Ce n'est même pas un opérateur JavaScript si je ne me trompe pas.

Quelqu'un peut-il expliquer ce que c'est et pourquoi est-il utilisé?

Mettre à jour:

C'est en fait une partie de celle-ci react-reduxqui sert à connecter un composant React à un magasin Redux.

Salman
la source
6
Je ne connais pas Redux, mais il ressemble à un décorateur. medium.com/google-developers/…
Lee
4
J'adore comment dans ce nouveau monde JavaScript, vous regardez le code la moitié du temps et pensez "quelle partie de la syntaxe du langage est-ce?"
MK.
4
Lol, je suis profondément plongé dans le redux et tout ça. Mais à l'époque, je ne savais pas que la syntaxe du décorateur n'avait rien à voir avec redux. C'est juste du JavaScript. Heureux de voir que cette question aide beaucoup de gens comme moi. :)
Salman
1
Apparemment, l'équipe redux décourage l'utilisation de connect en tant que décorateur pour le moment github.com/happypoulp/redux-tutorial/issues/87
Syed Jafri

Réponses:

376

Le @symbole est en fait une expression JavaScript actuellement proposée pour désigner les décorateurs :

Les décorateurs permettent d'annoter et de modifier les classes et les propriétés au moment du design.

Voici un exemple de configuration de Redux sans et avec un décorateur:

Sans décorateur

import React from 'react';
import * as actionCreators from './actionCreators';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';

function mapStateToProps(state) {
  return { todos: state.todos };
}

function mapDispatchToProps(dispatch) {
  return { actions: bindActionCreators(actionCreators, dispatch) };
}

class MyApp extends React.Component {
  // ...define your main app here
}

export default connect(mapStateToProps, mapDispatchToProps)(MyApp);

Utiliser un décorateur

import React from 'react';
import * as actionCreators from './actionCreators';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';

function mapStateToProps(state) {
  return { todos: state.todos };
}

function mapDispatchToProps(dispatch) {
  return { actions: bindActionCreators(actionCreators, dispatch) };
}

@connect(mapStateToProps, mapDispatchToProps)
export default class MyApp extends React.Component {
  // ...define your main app here
}

Les deux exemples ci-dessus sont équivalents, c'est juste une question de préférence. De plus, la syntaxe du décorateur n'est pas encore intégrée dans les runtimes Javascript, et est toujours expérimentale et sujette à changement. Si vous souhaitez l'utiliser, il est disponible via Babel .

Tanner Semerad
la source
46
c'est génial
svnm
2
On peut même être plus concis avec la syntaxe ES6. @connect (state => {return {todos: state.todos};}, dispatch => {return {actions: bindActionCreators (actionCreators, dispatch)};})
LessQuesar
11
Si vous voulez vraiment être concis, vous pouvez utiliser des retours implicites dans ES6. Cela dépend de la façon dont vous voulez être explicite. @connect(state => ({todos: state.todos}), dispatch => ({actions: bindActionCreators(actionCreators, dispatch)}))
Tanner Semerad
3
Comment exporter le composant non connecté pour des tests unitaires?
tim
L'utilisation de Decorator pour Redux avec React-Navigation peut être problématique, la meilleure pratique actuelle consiste à utiliser la fonction et non le décorateur: github.com/react-community/react-navigation/issues/1180
straya
50

Très important!

Ces accessoires sont appelés accessoires d'état et ils sont différents des accessoires normaux, toute modification apportée aux accessoires d'état de votre composant déclenchera la méthode de rendu du composant encore et encore, même si vous n'utilisez pas ces accessoires.Par conséquent, pour des raisons de performances, essayez de vous lier à votre composant uniquement les accessoires d'état dont vous avez besoin à l'intérieur de votre composant et si vous utilisez un accessoire secondaire, ne liez que ces accessoires.

exemple: disons qu'à l'intérieur de votre composant vous n'avez besoin que de deux accessoires:

  1. le dernier message
  2. l'identifiant

ne fais pas ça

@connect(state => ({ 
   user: state.user,
   messages: state.messages
}))

fais ça

@connect(state => ({ 
   user_name: state.user.name,
   last_message: state.messages[state.messages.length-1]
}))
Alnamrouti à prix réduit
la source
9
ou utilisez des sélecteurs comme resélection ou fastmemoize
Julius Koronci