开发者问题收集

React + Redux:TypeError:无法读取未定义的属性“push”

2018-09-10
1330

我开始使用 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

2个回答

您应该使用

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

而不是

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

这里是 文档

因此,我认为您的示例中的 this.props.historyundefined

Olivier Boissé
2018-09-11

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

Dimitrih
2018-09-11