6
votes

While learning about React-Redux I stumbled across the following code where I am not sure what's the difference between the following two lines and using mapDispatchToProps?

    let { dispatch, actions } = this.props;
    dispatch(actions.createTodo({ todo }));

Can someone please tell me the difference in using the above two lines and using mapDispatchToProps? Also can the above two lines be used in components, containers or only in components? Thanks

import React from 'react';
import ReactDOM from 'react-dom';

export default class TodoForm extends React.Component {
  createTodo(e) {
    e.preventDefault();

    let input = ReactDOM.findDOMNode(this.input);
    let todo = input.value;

    // ????
    let { dispatch, actions } = this.props;
    dispatch(actions.createTodo({ todo }));

    input.value = '';
  }

  render() {
    return (
      <div>
        <Form horizontal onSubmit={::this.createTodo}>

        </Form>
      </div>
    );
  }
}
3
Is that the full example? where is the connect? - Mayday
Yes this is all the code, I only removed HTML input elements between the two Form tags, nothing more. No connect function - MChan

3 Answers

8
votes

You can either use dispatch and not pass mapDispatchToProps, or you can use the props injected by mapDispatchToProps, and not use dispatch. This is why mapDispatchToProps is called this way—it lets you define some other props based on dispatch so you don’t need to use it again.

Here is an example which is using mapDispatchToProps approach. You may find the code here.

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { toggleQuestionModal, toggleConfirmation } from '../actions/questionActions';
import QuestionModal from '../components/questionModal';

class QuestionPage extends Component {
    constructor(props, context) {
        super(props, context);
        this.openModal = this.openModal.bind(this);
        this.closeModal = this.closeModal.bind(this);
        this.afterOpenModal = this.afterOpenModal.bind(this);
    }


    openModal() {
        this.props.toggleQuestionModal(true);
    }

    afterOpenModal() {
        // references are now sync'd and can be accessed. 
        // this.subtitle.style.color = '#f00';
    }

    closeModal() {
        this.props.toggleConfirmation(true);
    }

    render() {
        const { modalIsOpen } = this.props;
        return (
            <div>
                <QuestionModal modalIsOpen={modalIsOpen} openModal={this.openModal} closeModal={this.closeModal} 
                afterOpenModal={this.afterOpenModal} />
            </div>
        );
    }
}

QuestionPage.propTypes = {
    modalIsOpen: PropTypes.bool.isRequired,
    toggleQuestionModal: PropTypes.func.isRequired,
    toggleConfirmation: PropTypes.func.isRequired
};

function mapStateToProps(state, ownProps) {
    return {
        modalIsOpen: state.question.modalIsOpen
    };
}

function mapDispatchToProps(dispatch) {
    return {
        toggleQuestionModal: bindActionCreators(toggleQuestionModal, dispatch),
        toggleConfirmation: bindActionCreators(toggleConfirmation, dispatch)
    };
}

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

This is the recommended approach. When you pass mapDispatchToProps to the connect helper, your action is bound to the props. Hence you can call it using this.props.yourAction.

The other approach is to dispatch the action directly to the store. You can do it like this.

    import {loadCourses} from './actions/courseActions';
    import configureStore from './store/configureStore';

    const store = configureStore();
    store.dispatch(loadCourses());

The configureStore file for a dev environment would be something like this.

import { createStore, applyMiddleware } from 'redux';
import rootReducer from '../reducers';
import reduxImmutableStateInvariant from 'redux-immutable-state-invariant';
import thunk from 'redux-thunk';

export default function configureStore(initialState) {
  return createStore(
    rootReducer,
    initialState,
    applyMiddleware(thunk, reduxImmutableStateInvariant())
  );
}

Also notice that here I am using redux-thunk middleware. Apart from the above explanation, I would like to recommend you to go through this discussion as well. Hope this helps. happy coding !

1
votes

react-redux provides react bindings for redux. You don't have to use it in order to use redux but it makes all the binding and optimizations under the hood for you.

Instead of manually

  • dispatching your action
  • listening to the store
  • update the state when the store changes

You just connect your component to the redux store with connect() and you're done. connect() will give you back a component where all the dispatch and state values you need will be accessible in the components's props.

0
votes

mapDispatchToProps is used to bind your actions to a store. Usually action creators are completely indepedent from any store. This way the actions can be tested easily.

In Redux you have one central store that gets initialised once in your components lifecycle. react-redux provides a way to access this store in all the components that need to access the store in a higher order component (connect). The store has two main functions: getState() and dispatch(action).

  • Holds application state;
  • Allows access to state via getState();
  • Allows state to be updated via dispatch(action);

Redux store documentation

react-redux's connect function wraps a component and injects properties into the component. Some of those properties are always inserted and you cannot choose them like dispatch. The function also accepts two parameters. One of them is the well known mapStateToProps. This is your selector function to decide which parts of the store you want to receive inside of your component as properties. The second parameter can either be an object of action creators or a function that receives the dispatch function and also returns an object that gets merged into the properties of your component. This allows for components that are unaware of the concept of Redux and just take properties.

Redux documentation with React and connect documentation in react-redux repository

I created a minimal react-redux example on codesandbox.io. Feel free to play around with different versions of calling actions.

One note on containers and components: I would not worry about best practices until you fully understand what redux is doing. This concept also is not that important to Redux anyways.