What's the '@' (at symbol) in the Redux @connect decorator?

66,277

Solution 1

The @ symbol is in fact a JavaScript expression currently proposed to signify decorators:

Decorators make it possible to annotate and modify classes and properties at design time.

Here's an example of setting up Redux without and with a decorator:

Without a decorator

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);

Using a decorator

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
}

Both examples above are equivalent, it's just a matter of preference. Also, the decorator syntax isn't built into any Javascript runtimes yet, and is still experimental and subject to change. If you want to use it, it is available using Babel.

Solution 2

Very Important!

These props are called state props and they are different from normal props, any change to your component state props will trigger the component render method again and again even if you don't use these props so for Performance Reasons try to bind to your component only the state props that you need inside your component and if you use a sub props only bind these props.

example: lets say inside your component you only need two props:

  1. the last message
  2. the user name

don't do this

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

do this

@connect(state => ({ 
   user_name: state.user.name,
   last_message: state.messages[state.messages.length-1]
}))
Share:
66,277

Related videos on Youtube

Salman
Author by

Salman

Updated on August 12, 2020

Comments

  • Salman
    Salman almost 4 years

    I am learning Redux with React and stumbled upon this code. I am not sure if it is Redux specific or not, but I have seen the following code snippet in one of the examples.

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

    While the functionality of connect is pretty straightforward, but I don't understand the @ before connect. It isn't even a JavaScript operator if I am not wrong.

    Can someone explain please what is this and why is it used?

    Update:

    It is in fact a part of react-redux which is used to connects a React component to a Redux store.

    • Lee
      Lee over 8 years
      I'm not familiar with Redux, but it looks like a decorator. medium.com/google-developers/…
    • MK.
      MK. over 7 years
      I love how in this new JavaScript world you are staring at the code half of the time and thinking "what part of the language syntax is this?"
    • Salman
      Salman over 7 years
      Lol, I'm way deep into redux and stuff now. But back then I didn't know the decorator syntax has nothing to do with redux. Its just JavaScript. Glad to see this question is helping a lot of people like me. :)
    • Syed Jafri
      Syed Jafri over 7 years
      Apparently the redux team discourages the use of connect as a decorator at the moment github.com/happypoulp/redux-tutorial/issues/87
  • LessQuesar
    LessQuesar over 7 years
    One can even be more terse with ES6 syntax. @connect( state => { return { todos: state.todos }; }, dispatch => { return {actions: bindActionCreators(actionCreators, dispatch)}; } )
  • Tanner Semerad
    Tanner Semerad over 7 years
    If you really want to be terse you can use implicit returns in ES6. It depends on how explicit you want to be. @connect(state => ({todos: state.todos}), dispatch => ({actions: bindActionCreators(actionCreators, dispatch)}))
  • tim
    tim about 7 years
    How would you export the unconnected component for unit testing?
  • straya
    straya about 7 years
    Using decorator for redux with react-navigation can be problematic, current best-practice is to use the function not the decorator: github.com/react-community/react-navigation/issues/1180
  • Julius Koronci
    Julius Koronci almost 7 years
    or use selectors like reselect or fastmemoize
  • zloctb
    zloctb over 6 years
  • Subhadeep Banerjee
    Subhadeep Banerjee almost 6 years
    The examples are really helpful
  • vsync
    vsync over 5 years
    What does this mean "at design time"? Never heard this term design time. can you explain it?
  • serg06
    serg06 about 2 years
    Is this possible with functional components?