Redux Router - "Dispatch is not defined"
Asked Answered
B

3

13

I've got a simple component that calls an action when a user loads a page, and inside that action, I'm trying to dispatch another action to set the loggedIn state of the store to true or false:

import React, { Component } from 'react'
import { Link, browserHistory } from 'react-router'
import $ from 'jquery'

class Login extends Component {

  constructor(props) {
    super(props)
  }
  componentDidMount() {
    this.props.actions.guestLoginRequest()
  }
  render() {
    return (
      <div>
        <div classNameName="container">
          <div className="row">
            We are signing you in as a guest
          </div>
        </div>
      </div>
    )
  }
}

export default Login

I can get the login information when the guestLoginRequest action is called, but when I try to dispatch another action inside of it, nothing happens:

guestLoginRequest: function(){
    var ref = new Firebase("https://penguinradio.firebaseio.com");
    ref.authAnonymously(function(error, authData) {
      if (error) {
        console.log("Login Failed!", error);
      } else {
        console.log("Authenticated successfully with payload:", authData);
        return dispatch => {
          dispatch(actions.setLoginStatus(true, authData))
          console.log("dispatched");
        };
      }
    });
  }

I get an error of Uncaught ReferenceError: dispatch is not defined when I remove the return dispatch => { } statement. In my store I am using redux-thunk, so I can dispatch inside of actions:

// Store.js
import { applyMiddleware, compose, createStore } from 'redux'
import rootReducer from './reducers'
import logger from 'redux-logger'
import thunk from 'redux-thunk'

let finalCreateStore = compose(
  applyMiddleware(thunk, logger())
)(createStore)


export default function configureStore(initialState = { loggedIn: false }) {
  return finalCreateStore(rootReducer, initialState)
}

I am mapping the dispatch to props in my app.js as well:

function mapStateToProps(state) {
  return state
}
function mapDispatchToProps(dispatch) {
  return {
      actions: bindActionCreators(actions, dispatch)
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(App)

Just in case it could be helpful, here is my client.js and reducer files:

// client.js
import React from 'react'
import { render } from 'react-dom'
import App from '../components/App'
import configureStore from '../redux/store'
import { Provider } from 'react-redux'


let initialState = {
  loggedIn: false
}

let store = configureStore(initialState)

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('app')
)
// Reducer.js
import { combineReducers } from 'redux'

let LoginStatusReducer = function reducer(loggedIn = false, action) {
  switch (action.type) {
    case 'UPDATE_LOGIN_STATUS':
      return loggedIn = action.boolean
    default:
      return loggedIn
  }
}
export default LoginStatusReducer

const rootReducer = combineReducers({
  loggedIn: LoginStatusReducer
})

export default rootReducer

Any ideas why my dispatch function isn't working? I'm confused since I did set up redux-thunk with my store, and I'm using code similar to the docs when I call return dispatch => { }. Is there something I'm missing? Thank you in advance for any advice!

Bouie answered 6/4, 2016 at 21:2 Comment(0)
S
9

You need your action to return a function to utilize the thunk middleware, then redux will inject the dispatcher into it. You mixed your dispatcher invocation with the implementation detail. The following snippet fixes both defects.

guestLoginRequest: function(){
  return function (dispatch) {
    var ref = new Firebase("https://penguinradio.firebaseio.com");
    ref.authAnonymously(function(error, authData) {
      if (error) {
        console.log("Login Failed!", error);
      } else {
        console.log("Authenticated successfully with payload:", authData);
        dispatch(actions.setLoginStatus(true, authData))
        console.log("dispatched");
      }
    });
  }
}

In addition, you need to dispatch your action correctly on the Login class.

dispatch(this.props.actions.guestLoginRequest())

Your action invocation is always done by invoking dispatch. The flow should be something like this:

React component --> dispatch ---> API call (thunk middleware) --> dispatch ---> reducer
Sapor answered 6/4, 2016 at 21:6 Comment(3)
I've replaced my action with the one you posted above, and updated the dispatch call on Login.js, but I am getting a " dispatch is not defined" on the Login.js file. Do I have to pass in that function to the Login component? Also should I be calling return function (dispatch) instead of return function (dispatcher)?Bouie
You'll need to expose a wrapper around the store's dispatch (via mapDispatchToProps) or get the store's dispatcher directly (store.dispatch). Here's an implementation example: Component - github.com/mattlo/consultant-app/blob/master/src/client/… Store export - github.com/mattlo/consultant-app/blob/master/src/client/data/…Sapor
I've updated my answer to include my mapDispatchToProps function, does it look right?Bouie
C
2

First, you need to import

  • import { useDispatch } from "react-redux";

then call it.

  • const dispatch = useDispatch();

now you are ready for use.

Chevaldefrise answered 17/1, 2023 at 19:16 Comment(0)
D
0

Make sure useDispatch imported

import { useDispatch } from "react-redux";
Daviddavida answered 13/10, 2022 at 8:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.