4

I'm learning redux and see that the examples in the doc use connect in this signature:

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

But in other places from other repos I've also seen this-

@connect(mapStateToProps, mapDispatchToProps)

I get that there the same thing but how does the signature of a decorator work? It doesn't look like it's setting a variable to the result of the connect so where does the function of @connect go to and get assigned to?

stackjlei
  • 9,485
  • 18
  • 65
  • 113
  • 1
    Possible duplicate of [What does the at symbol do in ES6 javascript? (ECMAScript 2015)](http://stackoverflow.com/questions/31821084/what-does-the-at-symbol-do-in-es6-javascript-ecmascript-2015) – dork Apr 17 '17 at 07:28

2 Answers2

16

Decorators are just higher-order functions that work on the next thing that they see.

This is sort of cheating (not really sort of, it is), but if we simplified this to a format that you could reason about using just simple values:

const add = x => y => x + y;

Add is a function that expects an x, and returns a function that expects a y,
and then returns x + y;
You can call it like

add(1)(2); // 3

or

const add1 = add(1);
add1(2); // 3

But what if we had some way of telling JS not to expect to pass in the last value, but instead just run what it has on the next thing it sees.

@add(1)
2; // 3

@add1
2; // 3

Like I said, this example doesn't really work this way (in that a decorator function wouldn't really be meant for adding two numbers, so much as modifying classes or methods or parameters), but that is the basic concept behind the decorators.

@connect(mapProps, mapHandlers)
MyComponent;

is the same as saying

connect(mapProps, mapHandlers)(MyComponent);
Norguard
  • 26,167
  • 5
  • 41
  • 49
4

If you dont understand it in theory then maybe a visual will help. Lets say you are using redux-form and connect and react-autofill for a form on your page. you could use decorators to use it like so.

@connect(mapStateToProps, mapDispatchToProps)
@autofill
@reduxForm({form: 'somethingForm', enableReinitialize: true})
class Something extends React.Component {
    ....
} 

The equivalent of this without decorators would be

class Something extends React.Component {
    ....
}
Something = reduxForm({
    form: 'somethingForm',
    enableReinitialize: true
})(Something);
Something = connect(mapStateToProps, mapDispatchToProps)(autofill(Something));

so think of it like this. top to bottom is last to first order in terms of application for each function. you apply reduxForm, then autofill, then connect in both cases. the decorators just make it simpler to write and less messy code as well

John Ruddell
  • 25,283
  • 6
  • 57
  • 86
  • how do the decorators know to take `Something` as their argument? In your 2nd example, you have to pass `autofill(Something)` as an argument to connect, but how is that being done with the connector? – stackjlei Apr 19 '17 at 00:01
  • 1
    @stackjlei A decorator is decorating something. In this case its my class `Something` when you "decorate" anything it is the equivalent of calling a function and passing said anything through as the argument to the function. If you notice connect, reduxForm and autofill all three take the class Something as the argument. so you can decorate them all on the class – John Ruddell Apr 20 '17 at 07:23