4

i'm just getting into React-Redux. I successfully connected a few components to the store with mapDispatchToProps and mapStateToProps, so my setup seems to be correct. Now i have a stateless component with a button that should dispatch an action:

import React from 'react';
import RaisedButton from 'material-ui/RaisedButton';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { toggleSnackbar } from '../../store/actions';

const handleClick = props => {
    console.log(props.toggleSnackbar)
    props.toggleSnackbar("test")
}

const ButtonComponent = props =>
    (
      <div>
          <RaisedButton
            onClick={() => handleClick(props)}
          />
        </div>
      </div>
    );

const mapDispatchToProps = dispatch => bindActionCreators({
    toggleSnackbar,
}, dispatch);

export default connect(mapDispatchToProps)(muiThemeable()(ButtonComponent))

Now i get the error:

Uncaught TypeError: dispatch is not a function
    at Object.toggleSnackbar (bindActionCreators.js:3)
    at handleClick (BottomCTA.jsx:28)
    at Object.onClick (BottomCTA.jsx:61)
    at EnhancedButton._this.handleClick (EnhancedButton.js:144)
    at Object../node_modules/react-dom/lib/ReactErrorUtils.js.ReactErrorUtils.invokeGuardedCallback (ReactErrorUtils.js:69)
    at executeDispatch (EventPluginUtils.js:85)
    at Object.executeDispatchesInOrder (EventPluginUtils.js:108)
    at executeDispatchesAndRelease (EventPluginHub.js:43)
    at executeDispatchesAndReleaseTopLevel (EventPluginHub.js:54)
    at Array.forEach (<anonymous>)
    at forEachAccumulated (forEachAccumulated.js:24)
    at Object.processEventQueue (EventPluginHub.js:254)
    at runEventQueueInBatch (ReactEventEmitterMixin.js:17)
    at Object.handleTopLevel [as _handleTopLevel] (ReactEventEmitterMixin.js:27)
    at handleTopLevelImpl (ReactEventListener.js:72)
    at ReactDefaultBatchingStrategyTransaction.perform (Transaction.js:143)
    at Object.batchedUpdates (ReactDefaultBatchingStrategy.js:62)
    at Object.batchedUpdates (ReactUpdates.js:97)
    at dispatchEvent (ReactEventListener.js:147)

The console logs:

ƒ () {
    return dispatch(actionCreator.apply(undefined, arguments));
  }

toggleSnackbar action:

export function toggleSnackbar(message) {
  return {
    type: 'TOGGLE_SNACKBAR',
    payload: message,
  };
}

I cannot figure out what is wrong here?

Edit:

Here is another component in the same project that works just fine with the same aciton:

import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import RaisedButton from 'material-ui/RaisedButton';
import './BuyingFormContainer.css';
import { formatDollarToFloat } from '../../shared/formater';
import { BuyingForm } from '../';
import { buyTicket, toggleSnackbar } from '../../store/actions';
import { contentEn } from '../../assets';

const customButton = {
  buttonStyle: { borderRadius: '100px', height: '40px', lineHeight: '35px' },
  overlayStyle: { borderRadius: '100px' },
  style: { borderRadius: '100px', minWidth: '200px', color: '#fffff' },
};

const handleClick = (props) => {
    console.log(props.toggleSnackbar)
  props.buyTicket(formatDollarToFloat(props.buyingForm.values.buyingFormInput));
  //TODO: Trigger this after BUY_TICKET_SUCCESS
  props.toggleSnackbar("Prediction Recieved " + props.buyingForm.values.buyingFormInput)
}

const buyingFormContainer = props => (
  <div className="buyingForm__container" id={'buyingForm'}>
    <BuyingForm />
    <RaisedButton
      label={contentEn.topComponent.buttonLabel}
      style={customButton.style}
      buttonStyle={customButton.buttonStyle}
      overlayStyle={customButton.overlayStyle}
      className="buyingForm_raisedButton"
      secondary
      onClick={() => handleClick(props)}
    />
  </div>
);

buyingFormContainer.propTypes = {
  buyTicket: PropTypes.func.isRequired,
};

const mapStateToProps = state => ({
  buyingForm: state.form.buyingForm,
});

const mapDispatchToProps = dispatch => bindActionCreators({
  buyTicket,
  toggleSnackbar,
}, dispatch);

export default connect(mapStateToProps, mapDispatchToProps)(buyingFormContainer);
3
  • 1
    What does toggleSnackbar look like? Commented Oct 6, 2017 at 11:29
  • Updated my post. Please note that this action correctly dsipatches from another component already Commented Oct 6, 2017 at 11:35
  • Looks as though you have a difference in the connect code which could be causing the issue? Would maybe test without the muiThemeable() part first, and see if you can get to the bottom of it. Commented Oct 6, 2017 at 12:26

2 Answers 2

5

connect with an arity of 1 uses the only argument as mapStateToProps, not mapDispatchToProps:

function mapStateToProps(state) {
  return { todos: state.todos }
}

export default connect(mapStateToProps)(TodoApp)

Try passing null as the first argument:

export default connect(null, mapDispatchToProps)(...)
Sign up to request clarification or add additional context in comments.

Comments

0

Try something like in your toggleSnackbar action

export function toggleSnackbar(message) {
    return (dispatch) => {
        dispatch({
          type: 'TOGGLE_SNACKBAR',
          payload: message
        });
    }
}

Generally you don't need bindActionCreators usually returning an object is enough, try like:

const mapDispatchToProps = { toggleSnackbar };

And place your muiThemeable() before connect as

export default muiThemeable()(connect(null, mapDispatchToProps)(ButtonComponent))

2 Comments

problem still persits
@ReneFüchtenkordt - Try the updated answer. See if that helps you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.