【问题标题】:Redux - mapDispatchToProps not working for logout functionRedux - mapDispatchToProps 不适用于注销功能
【发布时间】:2018-06-07 10:58:47
【问题描述】:

在我的应用程序中,我有一个注销按钮,但它不会将您注销。我检查了减速器和动作,它们看起来还不错,因为我有另一个类似的应用程序,它在那里工作。

这是导入注销操作的“Nav.jsx”组件。

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)

当我运行这个时,console.log 给我“这是注销吗?ƒ () { [native code] }”,我也收到这个警告:“哈希历史不能推送相同的路径;新条目不会被添加到历史堆栈”。这是一个我现在自己在做的小组项目,我不知道到底出了什么问题?请帮忙。

如果有帮助,这里是注销操作。

   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())
      }
    }

这里还有一些来自应用程序的文件。这是 reducers 文件夹中的 auth.js。

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

还有结合reducer 的index.js。

从“redux”导入 {combineReducers}

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

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

【问题讨论】:

  • logoutUser 是 API 调用或简单的函数
  • 您已将您的调度映射到道具,因此您不能在该组件中使用this.props.dispatch。考虑到这一点,您应该在您的logout() 函数中使用this.props.logout。尝试更新您的代码,看看会发生什么。此外,您的react-router 似乎有问题。

标签: javascript reactjs redux logout react-props


【解决方案1】:

因为你已经在使用mapDispatchToProps,所以你需要直接调用该函数而不是使用dispatch,如果你不提供mapDispatchToPropsdispatch将提供给组件

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)

【讨论】:

    【解决方案2】:

    我很困惑为什么您同时使用组件状态和 redux 状态来跟踪用户是否已注销。无论如何,您将 dispatch 传递给 mapDispatchToProps,并且应该使用 dispatch() 将您在 mapDispatchToProps 中定义的函数包装起来,以便将它们发送给调度程序:

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

    使用这种模式可以让您将所有调度调用集中在mapDispatchToProps 中。

    完整的减速器(我将状态初始化为已登录,因为我无权访问您实际验证用户的身份验证模块):

    const initialState = {
      isAuthenticated: true,
      isFetching: false,
    }
    
    const logoutReducer = (state = initialState, action) => {
      switch (action.type) {
        case 'LOGOUT_REQUEST':
          return Object.assign({}, state, {
            isFetching: true,
          })
        case 'LOGOUT_SUCCESS':
          return Object.assign({}, state, {
            isFetching: false,
            isAuthenticated: false,
          })
        default:
          return state;
      }
    }
    
    export default logoutReducer;
    

    Reducer 安装在身份验证状态:

    import { combineReducers } from 'redux';
    import logoutReducer from './logoutReducer';
    
    export const rootReducer = combineReducers({
      auth: logoutReducer,
    });
    

    完全注销操作:

    const requestLogout = () => ({
      type: 'LOGOUT_REQUEST',
      isFetching: true,
      isAuthenticated: true
    })
    
    const receiveLogout = () => ({
      type: 'LOGOUT_SUCCESS',
      isFetching: false,
      isAuthenticated: false
    })
    
    export const logoutUser = () => {
      return dispatch => {
        document.location = "/#/"
        dispatch(requestLogout())
        //removeUser()
        dispatch(receiveLogout())
      }
    }
    

    完整组件:

    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: true,
          loggedOut: false
        }
        this.toggleBurger = this.toggleBurger.bind(this)
        this.logout = this.logout.bind(this)
      }
      toggleBurger() {
        this.setState({showBurger: !this.state.showBurger})
      }
    
      logout () {
        console.log('logging out')
        this.props.logout()
        this.setState({loggedOut: true})
      }
    
      render() {
        //
        const {auth} = this.props
        const {loggedOut} = this.state
        console.log('is this logout?', this.logout)
    
        return <nav className='navbar'>
          <div className='container'>
            <div className='navbar-brand' style={{
                height: '40px',
                width: '40px',
                background: 'red',
              }}>
              <span onClick={this.toggleBurger}
                className={
                  `navbar-burger burger ${this.state.showBurger ? 'is-active': ''}`
                } data-target='navbarMenuHeroA'>
                <span></span>
                <span></span>
                <span></span>
              </span>
            </div>
            <div id='navbarMenuHeroA' 
              className={
                `navbar-menu ${this.state.showBurger ? 'is-active' : ''}`
              }>
              <div className='navbar-end'>
                <Link onClick={this.toggleBurger}
                  className='navbar-item'
                  to='/found'>Found</Link>
                <Link onClick={this.toggleBurger}
                  className='navbar-item'
                  to='/lost'>Lost</Link>
                {auth.isAuthenticated
                  ? <span>
                    <Link onClick={this.toggleBurger}
                      className='navbar-item'
                      to='/foundform'>Foundform</Link>
                    <Link onClick={this.toggleBurger}
                      className='navbar-item'
                      to='/lostform'>Lostform</Link>
                    <Link onClick={this.logout}
                      className='navbar-item'
                      to='/'>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 => ({
      logout: () => dispatch(logoutUser())
    })
    
    const mapStateToProps = state => ({
      auth: state.auth,
    })
    
    export default connect(mapStateToProps, mapDispatchToProps)(Nav)
    

    我认为在继续或在 StackOverflow 上提问之前,您需要大大简化。用一个 div 制作一个简单的组件应用程序,允许用户单击登录和单击注销。然后一一介绍元素。当您遇到困难时,将应用程序削减到其对问题的绝对最小可行表达,并将其作为问题发布在这里,人们会很乐意提供帮助...

    【讨论】:

    • 大家好,感谢您的回答,但我仍然遇到同样的错误。
    • @Jattsingh 这是你第一次接触 React(或 React Router 或 Redux)吗?这段代码似乎很混乱;我强烈建议先尝试构建一个更简单的用例,然后再构建此身份验证组件...
    • @Jattsingh 你看我更新的答案了吗?尝试使用create-react-app 或一些绝对最小的样板文件并实现上述内容,您应该会看到更改工作......
    • 感谢您的所有回答,但问题可能出在其他地方,我添加了更多代码。这是一个小组项目,但我主要从事 react 方面的工作,redux 对我来说仍然很新。
    • @Jattsingh 您是否使用了 create-react-app 并使用了我在上面粘贴的组件?如果是这样,您遇到了什么问题?如果没有,我认为你应该尝试这个来隔离你遇到的问题......
    猜你喜欢
    • 2015-03-31
    • 2023-03-02
    • 1970-01-01
    • 2013-05-10
    • 2017-10-14
    • 1970-01-01
    • 2012-06-25
    • 2018-03-12
    相关资源
    最近更新 更多