Як отримати просту розсилку від this.props за допомогою підключення w / Redux?


107

У мене є простий компонент React, який я підключаю (відображення простого масиву / стану). Щоб не посилатися на контекст для магазину, я хотів би спосіб отримати "відправлення" безпосередньо з реквізиту. Я бачив інших, хто використовує такий підхід, але не мають до цього доступу з якоїсь причини :)

Ось версії кожної залежності від npm, яку я зараз використовую

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

Ось компонентний метод w / connect

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

Якщо вам потрібно подивитися, як налаштований мій маршрутизатор w / redux

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. Коли все, що ви робите, це повернення 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 btw - другий параметр в bindActionCreators(actionCreators, dispatch)необов’язковій? Я помітив у вашому коді в // es7 spread syntaxрядку, цей dispatchbindActionCreators
знак

що є внутрішнім методом збільшення?
Хуршид Ансарі

Синтаксис поширення es7 повинен бути function mapDispatchToProps(dispatch) { return { ...bindActionCreators({ increment, decrement }), dispatch }; }
Чорний

6

Зазвичай ви можете змішувати та поєднувати залежно від того, що хочете.

Ви можете передати dispatchяк опору, якщо це саме те, що ви хочете:

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

Я не впевнений, як fetchUsersце використовується (як функція асинхронізації?), Але ви зазвичай використовуєте щось на зразок bindActionCreatorsдля автоматичного прив'язування відправки, і тоді вам не доведеться турбуватися про використання dispatchбезпосередньо в підключених компонентах.

Використовуючи dispatchкаталогічне сполучення пар, німий , бездержавний компонент зі скороченням. Що може зробити його менш портативним.


3
Те, що ви пропонуєте, не спрацює. Ви отримаєте незв'язане fetchUsersвведення в якості опори. Позначення ярлика працює лише тоді, коли ви передаєте об'єкт як другий аргумент. При передачі функції ви повинні викликати bindActionCreatorsсебе: dispatch => ({ ...bindActionCreators({ fetchUsers }, dispatch), dispatch }).
Дан Абрамов

Чому поширюватись та передаватись у відправці безпосередньо у bindActionCreators? dispatch => ( bindActionCreators({ dispatch, fetchUsers }, dispatch))
користувач3711421

2

Хоча ви можете переходити dispatchвниз як частина dispatchToProps, я рекомендую уникати доступу до компонентів storeабо dispatchбезпосередньо з них. Здається, вам краще послужити, передавши в аргумент зв’язку дії 2-й аргументdispatchToProps

Дивіться приклад, який я розмістив тут https://stackoverflow.com/a/34455431/2644281 про те, як передати "вже пов'язаного творця дій" таким чином, вашим компонентам не потрібно безпосередньо знати про це або залежати від магазину / відправки. .

Вибачте, що коротко. Я оновлю w / докладнішу інформацію.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.