Redux - mapDispatchToProps не работает для функции выхода из системы - PullRequest
0 голосов
/ 07 июня 2018

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

Это компонент 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]}», и я также получаю это предупреждение: «Хэш-история не может PUSH по тому же пути; новая запись не будет добавлена ​​в стек истории ".Это был групповой проект, над которым я сейчас работаю, и я не могу сказать, что именно не так?Пожалуйста помоги.

Вот действие по выходу из системы, если оно помогает.

   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 в папке Redurs.

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, где были объединены редукторы.

import {integraReducers} из 'redux'

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

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

Ответы [ 2 ]

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

0 голосов
/ 07 июня 2018

Вам нужно вызывать функцию напрямую, а не использовать диспетчеризацию, поскольку вы уже используете 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)
...