Как получить простую рассылку из this.props с помощью connect w / Redux?

107

У меня есть простой компонент React, который я подключаю (отображая простой массив / состояние). Чтобы не ссылаться на контекст для магазина, я хотел бы иметь способ получать "отправку" непосредственно из props. Я видел, как другие использовали этот подход, но по какой-то причине не имели к нему доступа :)

Вот версии каждой зависимости npm, которую я использую в настоящее время

"react": "0.14.3",
"react-redux": "^4.0.0",
"react-router": "1.0.1",
"redux": "^3.0.4",
"redux-thunk": "^1.0.2"

Вот компонент с методом подключения

class Users extends React.Component {
    render() {
        const { people } = this.props;
        return (
            <div>
                <div>{this.props.children}</div>
                <button onClick={() => { this.props.dispatch({type: ActionTypes.ADD_USER, id: 4}); }}>Add User</button>
            </div>
        );
    }
};

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

export default connect(mapStateToProps, {
    fetchUsers
})(Users);

Если вам нужно увидеть редуктор (ничего интересного, но вот он)

const initialState = {
    people: []
};

export default function(state=initialState, action) {
    if (action.type === ActionTypes.ADD_USER) {
        let newPeople = state.people.concat([{id: action.id, name: 'wat'}]);
        return {people: newPeople};
    }
    return state;
};

Если вам нужно посмотреть, как мой роутер настроен с редукцией

const createStoreWithMiddleware = applyMiddleware(
      thunk
)(createStore);

const store = createStoreWithMiddleware(reducers);

var Route = (
  <Provider store={store}>
    <Router history={createBrowserHistory()}>
      {Routes}
    </Router>
  </Provider>
);

Обновить

похоже, что если я опущу свою собственную отправку в подключении (в настоящее время я показываю fetchUsers), я бы получил бесплатную отправку (просто не уверен, что так обычно работает настройка с асинхронными действиями). Люди смешиваются и сочетаются друг с другом, или все или ничего?

[mapDispatchToProps]

Торан Биллапс
источник

Ответы:

280

По умолчанию mapDispatchToPropsпросто dispatch => ({ dispatch }).
Поэтому, если вы не укажете второй аргумент connect(), вы будете dispatchвведены в качестве опоры в свой компонент.

Если вы передадите пользовательскую функцию в mapDispatchToProps, вы сможете делать с ней все, что угодно.
Несколько примеров:

// inject onClick
function mapDispatchToProps(dispatch) {
  return {
    onClick: () => dispatch(increment())
  };
}

// inject onClick *and* dispatch
function mapDispatchToProps(dispatch) {
  return {
    dispatch,
    onClick: () => dispatch(increment())
  };
}

Чтобы сэкономить вам время на вводе текста, Redux bindActionCreators()позволяет вам включить это:

// injects onPlusClick, onMinusClick
function mapDispatchToProps(dispatch) {
  return {
    onPlusClick: () => dispatch(increment()),
    onMinusClick: () => dispatch(decrement())
  };
}

в это:

import { bindActionCreators } from 'redux';

// injects onPlusClick, onMinusClick
function mapDispatchToProps(dispatch) {
  return bindActionCreators({
    onPlusClick: increment,
    onMinusClick: decrement
  }, dispatch);
}

или даже короче, если имена реквизитов совпадают с именами создателей действий:

// injects increment and decrement
function mapDispatchToProps(dispatch) {
  return bindActionCreators({ increment, decrement }, dispatch);
}

Если хотите, можете добавить dispatchтуда вручную:

// injects increment, decrement, and dispatch itself
function mapDispatchToProps(dispatch) {
  return {
    ...bindActionCreators({ increment, decrement }), // es7 spread syntax
    dispatch
  };
}

Официального совета о том, следует ли вам это делать или нет, нет. connect()обычно служит границей между компонентами, поддерживающими Redux, и компонентами, не поддерживающими Redux. Вот почему мы обычно чувствуем, что не имеет смысла вводить одновременно создателей связанных действий и dispatch. Но если вы чувствуете, что вам нужно это сделать, не стесняйтесь.

Наконец, шаблон, который вы сейчас используете, - это еще более короткий путь, чем вызов bindActionCreators. Когда все, что вы делаете, это return bindActionCreators, вы можете опустить вызов, поэтому вместо этого:

// injects increment and decrement
function mapDispatchToProps(dispatch) {
  return bindActionCreators({ increment, decrement }, dispatch);
}

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

можно записать как это

export default connect(
  mapStateToProps,
  { increment, decrement } // injects increment and decrement
)(App);

Однако вам придется отказаться от этого красивого короткого синтаксиса, когда вам понадобится что-то более индивидуальное, например, передача dispatch.

Дан Абрамов
источник
2
@DanAbramov, кстати, второй параметр bindActionCreators(actionCreators, dispatch)необязательный? Я заметил в вашем коде в // es7 spread syntaxстроке, что dispatchне передаетсяbindActionCreators
yonasstephen
что внутри метода приращения?
Хуршид Ансари
синтаксис es7 spread должен быть function mapDispatchToProps(dispatch) { return { ...bindActionCreators({ increment, decrement }), dispatch }; }
Black
6

Обычно вы можете смешивать и сочетать в зависимости от того, что вам нужно.

Вы можете выступить dispatchв качестве опоры, если хотите:

export default connect(mapStateToProps, (dispatch) => ({
    ...bindActionCreators({fetchUsers}, dispatch), dispatch
}))(Users);

Я не знаю , как fetchUsersиспользуется ( в качестве функции асинхронной?), Но, как правило , использовать что - то вроде bindActionCreatorsдля автоматической привязки отправки , а затем вам не придется беспокоиться об использовании dispatchнепосредственно в компонентах связности.

Использование dispatchкаталогового типа объединяет тупой компонент без состояния с redux. Что может сделать его менее портативным.

Дэвин Трайон
источник
3
То, что вы предлагаете, не сработает. Вы получите несвязанный, fetchUsersвведенный в качестве опоры. Обозначение ярлыка работает только тогда, когда вы передаете объект в качестве второго аргумента. При передаче функции вы должны вызвать bindActionCreatorsсебя: dispatch => ({ ...bindActionCreators({ fetchUsers }, dispatch), dispatch }).
Дэн Абрамов
Зачем распространять и передавать в рассылке непосредственно в bindActionCreators? dispatch => ( bindActionCreators({ dispatch, fetchUsers }, dispatch))
user3711421 07
2

Хотя вы можете передавать dispatchкак часть dispatchToProps, я бы рекомендовал избегать доступа к storeили dispatchнепосредственно из ваших компонентов. Похоже, вам лучше было бы передать создателя связанного действия во втором аргументе подключенияdispatchToProps

См. Пример, который я разместил здесь https://stackoverflow.com/a/34455431/2644281, о том, как передать "уже связанный создатель действия", таким образом, вашим компонентам не нужно напрямую знать или зависеть от хранилища / отправки. .

Извините за краткость. Я обновлю с дополнительной информацией.

Эрик Айбар
источник