Ad

Redux - MapDispatchToProps Not Working For Logout Function

in my app I've a logout button but it does not log you out. I've checked the reducers and the actions and they seem okay as I've another similar app and it works there.

This is the "Nav.jsx" component where the logout action is being imported.

import React from 'react'
import {connect} from 'react-redux'
import {Link} from 'react-router-dom'
import {logoutUser} from '../actions/logout'

class Nav extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      showBurger: false,
      loggedOut: false
    }
    this.toggleBurger = this.toggleBurger.bind(this)
    this.logout = this.logout.bind(this)
  }
  toggleBurger() {
    this.setState({showBurger: !this.state.showBurger})
  }

  logout () {
    this.props.dispatch(logoutUser())
    this.setState({loggedOut: true})
  }

  render() {
    //
    const {auth} = this.props
    const {showBurger} = this.state
    const {loggedOut} = this.state
    console.log("is this logout?", this.logout.bind(this))

    return <nav className="navbar">
      <div className="container">
        <div className="navbar-brand">
          <span onClick={this.toggleBurger} className={`navbar-burger burger ${showBurger ? 'is-active': ''}`} data-target="navbarMenuHeroA">
            <span></span>
            <span></span>
            <span></span>
          </span>
        </div>
        <div id="navbarMenuHeroA" className={`navbar-menu ${showBurger ? "is-active" : ''}`}>
          <div className="navbar-end">
            <Link onClick={this.toggleBurget} className="navbar-item" to='/found'>Found</Link>
            <Link onClick={this.toggleBurget} className="navbar-item" to='/lost'>Lost</Link>
            {auth.isAuthenticated
              ? <span>
                <Link onClick={this.toggleBurget} className="navbar-item" to='/foundform'>Foundform</Link>
                <Link onClick={this.toggleBurget} className="navbar-item" to='/lostform'>Lostform</Link>
                <Link to="/" onClick={() => this.logout.bind(this)} className="navbar-item">Logout</Link>
              </span>
              : [
                <Link onClick={this.toggleBurger} className="navbar-item is-large" to='/login'>Login</Link>,
                <Link onClick={this.toggleBurger} className="navbar-item" to='/register'>Register</Link>,
              ]
            }
          </div>
        </div>
      </div>
    </nav>
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    logout: () => dispatch(logoutUser())
  }
}

const mapStateToProps = ({auth}) => {
  return {auth}
}

export default connect(mapStateToProps, mapDispatchToProps)(Nav)

When I run this, the console.log give me "is this logout? ƒ () { [native code] }" and I also get this warning: "Hash history cannot PUSH the same path; a new entry will not be added to the history stack". This was a group project that I'm now working on myself and I can't tell what exactly is wrong? Please help.

Here is the logout action if it helps.

   import { removeUser } from '../utils/auth'
    function requestLogout () {
      return {
        type: 'LOGOUT_REQUEST',
        isFetching: true,
        isAuthenticated: true
      }
    }

    function receiveLogout () {
      return {
        type: 'LOGOUT_SUCCESS',
        isFetching: false,
        isAuthenticated: false
      }
    }

    // Logs the user out
    export function logoutUser () {
      return dispatch => {
        document.location = "/#/"
        dispatch(requestLogout())
        removeUser()
        dispatch(receiveLogout())
      }
    }

Here are some more files from the app.This is the auth.js in the reducers folder.

import { isAuthenticated, getUserTokenInfo } from '../utils/auth'

const initialState = {
  isFetching: false,
  isAuthenticated: isAuthenticated(),
  user: getUserTokenInfo(),
  errorMessage: ''
}

export default function auth (state = initialState, action) {
  switch (action.type) {
    case 'LOGIN_REQUEST':
      return {
        ...state,
        isFetching: true,
        isAuthenticated: false,
        errorMessage: ''
      }
    case 'LOGIN_SUCCESS':
      return {
        ...state,
        isFetching: false,
        isAuthenticated: true,
        user: action.user
      }
    case 'LOGIN_FAILURE':
      return {
        ...state,
        isFetching: false,
        isAuthenticated: false,
        errorMessage: action.message
      }
    case 'LOGOUT_SUCCESS':
      return {
        ...state,
        isFetching: false,
        isAuthenticated: false,
        user: null
      }
    case 'REGISTER_REQUEST':
      return {
        ...state,
        isFetching: true,
        isAuthenticated: false,
        errorMessage: ''
      }
    case 'REGISTER_FAILURE':
      return {
        ...state,
        isFetching: false,
        isAuthenticated: false,
        errorMessage: action.message
      }
    default:
      return state
  }
}

And the index.js where the reducers have been combined.

import {combineReducers} from 'redux'

import auth from './auth'
import lostPets from './lostPets'
import found from './foundPets'

export default combineReducers({
  auth,
  found,
  lostPets
})
Ad

Answer

You need to call the function directly instead of using dispatch since you are already using mapDispatchToProps, If you don't provide mapDispatchToProps, dispatch will be made available to the component

import React from 'react'
import {connect} from 'react-redux'
import {Link} from 'react-router-dom'
import {logoutUser} from '../actions/logout'

class Nav extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      showBurger: false,
      loggedOut: false
    }
    this.toggleBurger = this.toggleBurger.bind(this)
    this.logout = this.logout.bind(this)
  }
  toggleBurger() {
    this.setState({showBurger: !this.state.showBurger})
  }

  logout () {
    this.props.logout() // call logout here from props
    this.setState({loggedOut: true})
  }

  render() {
    //
    const {auth} = this.props
    const {showBurger} = this.state
    const {loggedOut} = this.state
    console.log("is this logout?", this.logout.bind(this))

    return <nav className="navbar">
      <div className="container">
        <div className="navbar-brand">
          <span onClick={this.toggleBurger} className={`navbar-burger burger ${showBurger ? 'is-active': ''}`} data-target="navbarMenuHeroA">
            <span></span>
            <span></span>
            <span></span>
          </span>
        </div>
        <div id="navbarMenuHeroA" className={`navbar-menu ${showBurger ? "is-active" : ''}`}>
          <div className="navbar-end">
            <Link onClick={this.toggleBurget} className="navbar-item" to='/found'>Found</Link>
            <Link onClick={this.toggleBurget} className="navbar-item" to='/lost'>Lost</Link>
            {auth.isAuthenticated
              ? <span>
                <Link onClick={this.toggleBurget} className="navbar-item" to='/foundform'>Foundform</Link>
                <Link onClick={this.toggleBurget} className="navbar-item" to='/lostform'>Lostform</Link>
                <Link to="/" onClick={() => this.logout.bind(this)} className="navbar-item">Logout</Link>
              </span>
              : [
                <Link onClick={this.toggleBurger} className="navbar-item is-large" to='/login'>Login</Link>,
                <Link onClick={this.toggleBurger} className="navbar-item" to='/register'>Register</Link>,
              ]
            }
          </div>
        </div>
      </div>
    </nav>
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    logout: () => dispatch(logoutUser())
  }
}

const mapStateToProps = ({auth}) => {
  return {auth}
}

export default connect(mapStateToProps, mapDispatchToProps)(Nav)
Ad
source: stackoverflow.com
Ad