Redux - mapDispatchToProps не работает для функции выхода из системы

в моем приложении у меня есть кнопка выхода из системы, но она не выходит из системы. Я проверил редукторы и действия, и они кажутся в порядке, поскольку у меня есть другое подобное приложение, и оно там работает.

Это компонент «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 выдает мне «это выход из системы? ƒ () { [собственный код]}», и я также получаю это предупреждение: «История хэшей не может НАЖАТЬ тот же путь; новая запись не будет добавлена ​​в стек истории». Это был групповой проект, над которым я сейчас работаю сам, и я не могу сказать, что именно не так? Пожалуйста помоги.

Вот действие выхода из системы, если это поможет.

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

Вот еще несколько файлов из приложения. Это 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
  }
}

И index.js, где редукторы были объединены.

импортировать {combineReducers} из «редукции»

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

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

person Jattsingh    schedule 07.06.2018    source источник
comment
logoutUser — это вызов API или просто функция   -  person RIYAJ KHAN    schedule 07.06.2018
comment
Вы сопоставили свою отправку с реквизитами, поэтому вы не можете использовать this.props.dispatch в этом компоненте. Учитывая это, вместо этого вы должны использовать this.props.logout в своей функции logout(). Попробуйте обновить свой код и посмотрите, что произойдет. Кроме того, похоже, у вас есть проблема с вашим react-router.   -  person ionizer    schedule 07.06.2018


Ответы (2)


Вам нужно вызвать функцию напрямую, а не использовать диспетчеризацию, поскольку вы уже используете mapDispatchToProps. Если вы не предоставите mapDispatchToProps, dispatch будет доступно для компонента.

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)
person Shubham Khatri    schedule 07.06.2018

Я не понимаю, почему вы используете как состояние компонента, так и состояние избыточности, чтобы отслеживать, вышел ли пользователь из системы. Несмотря на это, вы передаете dispatch в mapDispatchToProps и должны обернуть свои функции, которые вы определяете внутри mapDispatchToProps, с помощью dispatch(), чтобы они отправлялись диспетчеру:

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;

Редуктор монтируется в состоянии авторизации:

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, которое позволяет пользователям щелкнуть, чтобы войти в систему, и щелкнуть, чтобы выйти из нее. Затем по очереди вводите элементы. Когда вы застряли, сократите приложение до его абсолютного минимально жизнеспособного выражения проблемы и опубликуйте это как вопрос здесь, и люди будут рады помочь...

person duhaime    schedule 07.06.2018
comment
Привет всем, спасибо за ваши ответы, но я все еще получаю те же ошибки. - person Jattsingh; 08.06.2018
comment
@Jattsingh, это ваше первое знакомство с React (или с React Router или Redux)? Этот код кажется довольно запутанным; Я настоятельно рекомендую сначала попытаться создать более простой вариант использования, а затем перейти к этому компоненту аутентификации... - person duhaime; 08.06.2018
comment
@Jattsingh, ты посмотрел мой обновленный ответ? Попробуйте использовать create-react-app или какой-нибудь абсолютно минимальный шаблон и реализовать вышеизложенное, и вы должны увидеть, что изменения работают... - person duhaime; 09.06.2018
comment
Спасибо за все ваши ответы, но, возможно, проблема где-то еще, я добавил еще немного кода. Это был групповой проект, но я в основном работал над реакцией, а редуксы для меня все еще в новинку. - person Jattsingh; 13.06.2018
comment
@Jattsingh, вы использовали приложение create-react-app и использовали компоненты, которые я вставил выше? Если да, то с какими проблемами вы столкнулись? Если нет, я думаю, вам следует попробовать это, чтобы изолировать проблему, с которой вы столкнулись... - person duhaime; 13.06.2018
comment
Это работает, большое спасибо. Должно быть, это был mapStateToProps, который изначально был неправильным. Ваше здоровье. - person Jattsingh; 14.06.2018
comment
@Jattsingh ура! Я рад, что это вас заводит! Получайте удовольствие от изучения Redux. Учебники Egghead.io очень хороши, если вы еще не ознакомились с ними... - person duhaime; 14.06.2018
comment
@Jattsingh не стесняйтесь щелкать галочкой рядом с этим ответом, чтобы люди могли видеть, что эта проблема решена! - person duhaime; 20.06.2018