【问题标题】:React + Redux: TypeError: Cannot read property 'push' of undefinedReact + Redux:TypeError:无法读取未定义的属性“推送”
【发布时间】:2018-09-10 23:51:39
【问题描述】:

我从 ReactJS 和 Redux 开始,最近几天,当我让我的应用在浏览器中打开一段时间然后又回到它时,我遇到了一个问题,我看到了这个错误:

TypeError: Cannot read property 'push' of undefined

就在这里,在我的Event.js 组件中:

import React, { Component } from 'react';
import axios from 'axios';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { registerUser, logoutUser } from '../redux/actions/authentication';
import { withRouter } from 'react-router-dom';

class Event extends Component {
    constructor() {
        super();
        this.state = {
          ...
        }
    UNSAFE_componentWillMount() {
        if(!this.props.auth.isAuthenticated) {
            console.log('Unauthorized - Event action');
            this.props.history.push('/');
        }
    }
    componentDidMount() {
        axios.get('/api/events')
            .then((response) => {
                this.setState({events: response.data});
                console.log('events: ', this.state.events);
            }).catch(err => {
                console.log('CAUGHT IT! -> ', err);
            });
    }

    componentWillReceiveProps(nextProps) {
        if(nextProps.errors) {
            this.setState({
                errors: nextProps.errors
            });
        }
    }
    ...
    render() {
        const { errors } = this.state;
        const {isAuthenticated, user} = this.props.auth;

        return (...)
    }
Event.propTypes = {
    registerUser: PropTypes.func.isRequired,
    auth: PropTypes.object.isRequired,
    errors: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
    auth: state.auth,
    errors: state.errors
});

export default connect(mapStateToProps,{ registerUser })(withRouter(Event))

然后,我的redux/actions/authentication.js 看起来像这样:

import axios from 'axios';
import { GET_ERRORS, SET_CURRENT_USER } from './types'; // we list here the actions we'll use
import setAuthToken from '../../setAuthToken';
import jwt_decode from 'jwt-decode';

export const registerUser = (user, history) => dispatch => {
    axios.post('/api/users/register', user)
            .then(res => history.push('/login'))
            .catch(err => {
                dispatch({
                    type: GET_ERRORS,
                    payload: err.response.data
                });
            });
}

export const loginUser = (user) => dispatch => {
    axios.post('/api/users/login', user)
        .then(res => {
            //console.log(res.data);
            const { token } = res.data;
            localStorage.setItem('jwtToken', token);
            setAuthToken(token);
            const decoded = jwt_decode(token);
            dispatch(setCurrentUser(decoded));
        })
        .catch(err => {
            dispatch({
                type: GET_ERRORS,
                payload: err.response.data
            });
        });
}

export const setCurrentUser = decoded => {
    return {
        type: SET_CURRENT_USER,
        payload: decoded
    }
}

export const logoutUser = (history) => dispatch => {
    localStorage.removeItem('jwtToken');
    setAuthToken(false);
    dispatch(setCurrentUser({}));
    history.push('/login');
}

还有减速器 - authReducer.js:

import { SET_CURRENT_USER } from '../actions/types';
import isEmpty from '../../validation/is-empty';

const initialState = {
    isAuthenticated: false,
    user: {}
}

export default function(state = initialState, action) {
    switch(action.type) {
        case SET_CURRENT_USER:
            return {
                ...state,
                isAuthenticated: !isEmpty(action.payload),
                user: action.payload
            }
        default: 
            return state;
    }
}

errorReducer.js 是这样的:

import { GET_ERRORS } from '../actions/types';

const initialState = {};

export default function(state = initialState, action ) {
    switch(action.type) {
        case GET_ERRORS:
            return action.payload;
        default: 
            return state;
    }
}

index.js:

import { combineReducers } from 'redux';
import errorReducer from './errorReducer';
import authReducer from './authReducer';

export default combineReducers({
    errors: errorReducer,
    auth: authReducer
});

在 nabber 菜单中,我有一个注销用户的链接。如果用户点击链接,我会这样注销他:

onLogout(e) {
        e.preventDefault();
        this.props.logoutUser(this.props.history);
    }

但是,我仍然无法弄清楚为什么我会看到上述错误。我在这里也不明白的是,当我得到那个错误屏幕然后刷新页面时,错误页面消失了,我从localhost:3000/events重定向到localhost:3000

【问题讨论】:

  • 你能删除所有与历史无关的东西吗?如果这样做,您可能会自己发现错误。您似乎没有将历史记录传递给调用它的函数,但这不是一个最小的示例。

标签: reactjs redux


【解决方案1】:

你应该使用

withRouter(connect(...)(MyComponent))

而不是

connect(...)(withRouter(MyComponent))

这里是documentation

我认为 this.props.history 在您的示例中是 undefined,因此。

【讨论】:

  • @OliviewBoisse 谢谢,我刚刚测试了这个解决方案 - 不同之处在于我有一段时间不活动(比如一个小时)并且我用我的应用程序查看选项卡,所以我需要刷新页面,然后我看到错误 (TypeError: Cannot read property 'push' of undefined)。之前,我“不需要”刷新页面就可以看到这个错误......不幸的是它并没有解决问题。
  • 你能告诉我们你有logout函数的组件(nabber菜单)的代码吗?看看它是否用withRouter HOC 很好地声明了
【解决方案2】:

确保您传递给logoutUser 函数的对象不是未定义的,并且history 参数以正确的方式接收。您试图在 history 对象上调用 push 方法,但在这种情况下,它会告诉您无法找到该函数,因为 history 未定义。希望这会有所帮助。

【讨论】:

  • 好吧,我不明白是什么导致用户被重定向到该错误 - 代码的哪一部分会这样做。因为当我退出并尝试访问localhost:3000/events 时,我会立即重定向到localhost:3000。但是当我有一段时间不活动时,我会在不知道什么代码“重定向”我的情况下得到这个错误。
猜你喜欢
  • 2019-07-22
  • 1970-01-01
  • 2020-05-13
  • 2017-01-14
  • 2021-03-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多