Что такое '@' (в символе) в декораторе Redux @connect?

226

Я изучаю Redux с React и наткнулся на этот код. Я не уверен, если это специфичным для Redux или нет, но я видел следующий фрагмент кода в одном из примеров.

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

Хотя функциональность connect довольно проста, но я не понимаю, @прежде чем connect. Это даже не оператор JavaScript, если я не ошибаюсь.

Может кто-нибудь объяснить, пожалуйста, что это такое и почему оно используется?

Обновить:

Фактически это часть, react-reduxкоторая используется для подключения компонента React к хранилищу Redux.

Салман
источник
6
Я не знаком с Redux, но он выглядит как декоратор. medium.com/google-developers/…
Ли
4
Мне нравится, как в этом новом мире JavaScript вы смотрите на код половину времени и думаете: «Что это за синтаксис языка?»
МК.
4
Лол, я сейчас глубоко увлечен редукцией и прочим. Но тогда я не знал, что синтаксис декоратора не имеет ничего общего с избыточностью. Это просто JavaScript. Рад, что этот вопрос помогает многим таким людям, как я. :)
Салман
1
По-видимому, в настоящее время команда редуксов не рекомендует использовать
Сайед Джафри

Ответы:

376

@Символ в действительности выражение JavaScript предлагается в настоящее время для обозначения декораторов :

Декораторы позволяют аннотировать и изменять классы и свойства во время разработки.

Вот пример настройки Redux без и с декоратором:

Без декоратора

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

Использование декоратора

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
}

Оба приведенных выше примера эквивалентны, это просто вопрос предпочтений. Кроме того, синтаксис декоратора еще не встроен ни в одну среду исполнения Javascript и все еще является экспериментальным и может быть изменен. Если вы хотите использовать его, он доступен с помощью Babel .

Таннер Семерад
источник
46
это здорово
svnm
2
Можно даже быть более кратким с синтаксисом ES6. @connect (state => {return {todos: state.todos};}, dispatch => {return {actions: bindActionCreators (actionCreators, dispatch)};})
LessQuesar
11
Если вы действительно хотите быть кратким, вы можете использовать неявные возвращения в ES6. Это зависит от того, насколько явно вы хотите быть. @connect(state => ({todos: state.todos}), dispatch => ({actions: bindActionCreators(actionCreators, dispatch)}))
Таннер Семерад
3
Как бы вы экспортировали неподключенный компонент для модульного тестирования?
Тим
Использование декоратора для приведения с ответной навигацией может быть проблематичным, в настоящее время рекомендуется использовать функцию, а не декоратор: github.com/react-community/react-navigation/issues/1180
страя
50

Очень важно!

Эти реквизиты называются реквизитами состояния, и они отличаются от обычных реквизитов, любое изменение в реквизитах состояния вашего компонента будет снова и снова запускать метод рендеринга компонента, даже если вы не используете эти реквизиты, поэтому в целях повышения производительности попытайтесь привязать только к вашему компоненту реквизиты состояния, которые вам нужны внутри вашего компонента, и, если вы используете субпроп, привязывайте только эти реквизиты.

пример: скажем, внутри вашего компонента вам нужно только два реквизита:

  1. последнее сообщение
  2. Имя пользователя

не делай этого

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

сделай это

@connect(state => ({ 
   user_name: state.user.name,
   last_message: state.messages[state.messages.length-1]
}))
Фарид Алнамрути
источник
9
или используйте селекторы, такие как перевыбор или fastmemoize
Julius Koronci