在重定向出的页面中获取Redux状态错误



背景

我有一个使用JWT进行身份验证的事件页面。我在整个应用程序的标头中有一个注销功能。基本前提是,它是一个在用户和事件之间有多对多的事件显示应用程序。使用Mongo(如果重要的话(。

我点击所有页面上的注销,它运行得很好。然而,在Landing组件上,它抛出了此错误。

TypeError: Cannot read property 'id' of null
Function.stateToProps [as mapToProps]
Path/client/src/components/EventActionButton.js:69
66 | 
67 | const stateToProps = (state) => {   
68 |     return {
> 69 |         userId: state.user.id
70 |     }
71 | }
72 | 
View compiled
▼ 19 stack frames were expanded.
mapToPropsProxy
Path/client/node_modules/react-redux/es/connect/wrapMapToProps.js:41
handleNewPropsAndNewState
Path/client/node_modules/react-redux/es/connect/selectorFactory.js:30
handleSubsequentCalls
Path/client/node_modules/react-redux/es/connect/selectorFactory.js:56
pureFinalPropsSelector
Path/client/node_modules/react-redux/es/connect/selectorFactory.js:63
runComponentSelector [as run]
Path/client/node_modules/react-redux/es/components/connectAdvanced.js:21
Connect.componentWillReceiveProps
Path/client/node_modules/react-redux/es/components/connectAdvanced.js:152
callComponentWillReceiveProps
Path/client/node_modules/react-dom/cjs/react-dom.development.js:12399

Header.js(其中signout btn为(

import React , {Component} from 'react';
import {connect} from 'react-redux';
import {startSignOut} from '../actions/auth';
const Header = class Header extends Component {
handleSignOut = () => {
this.props.startSignOut();
}
render () {
return (
<div>
<span>circle</span>
<span>user</span>
<button onClick={() => this.handleSignOut()}>Sign out</button>
</div>
)  
}
}
const mapDispatchToProps = (dispatch) => ({
startSignOut: () => startSignOut(dispatch)
});
export default connect(undefined, mapDispatchToProps)(Header);

Landing.js(/URI的登录页(

import RequireAuth from './RequireAuth';
import {fetchEvents} from '../actions/event';
import {connect} from 'react-redux';
import EventItem from './EventItem';
import Header from './Header';
const EventDisplay = class EventDisplay extends Component {
componentDidMount = () => {
this.props.fetchEvents();
}
handleAddEvent = () => {
this.props.history.push('/addevent');
}
handleSignOut = () => {
this.props.startSignOut();
}
render() {
return (
<div>
<Header signOut={this.handleSignOut}/>
{
this.props.events.map((event, ind) => {
return <EventItem key={ind} history={this.props.history} index={ind + 1} event={event}/>
})
}
<button onClick={() => this.handleAddEvent()}>+</button>
</div>
)
}
}
const mapDispatchToProps = (dispatch) => ({
fetchEvents: (userId) => dispatch(fetchEvents(userId))
});
const mapStateToProps = (state) => ({
events: state.events
})
const connectedAuth = RequireAuth(connect(mapStateToProps, mapDispatchToProps)(EventDisplay));
export default connectedAuth;

EventItem.js(每个事件的可重用组件(

import EventActionButton from './EventActionButton';
import RequireAuth from './RequireAuth';
const EventItem = (props) => {
const event = props.event;
const handleDetailView = () => {
props.history.push({
pathname: "/eventview",
state: { event: props.event }
});
}
return (
<div>
<div onClick={() => handleDetailView()}>
<span >{event.title}</span>
<span>{event.description}</span>
<span>{event.host.first_name + " " + event.host.last_name}</span>
<span>{event.date}</span>
<span>{event.capacity}</span>
</div>
<EventActionButton displayEvent={event}/>
</div>
)
}
export default RequireAuth(EventItem);

EventActionButton.js(EventItem中允许用户参加或离开活动的按钮(

import {connect} from 'react-redux';
import {editEventAssociation} from '../actions/event';
import RequireAuth from './RequireAuth';
const EventActionButton = class EventActionButton extends Component {
constructor(props) {
super(props);
this.state ={
edit: false,
joined: false
}
}
onClick = (e) => {        
console.log(this.props);
var currentUser = this.props.userId;
if(this.state.edit) {
this.props.history.push('/addevent');
} else {
let userIds = this.props.displayEvent.users.map((user) => {
return user._id;
});
console.log(userIds);
if (this.state.joined) {
const modifiedUsers = userIds.filter((id) => id === this.props.userId);
userIds = modifiedUsers;
console.log(userIds);
} else {
userIds.push(this.props.userId);
console.log(userIds);
}
console.log("Joined " + this.state.joined);
console.log("Edited " + this.state.edit);
this.props.editEventAssociation(this.props.displayEvent._id, userIds, currentUser, this.state.joined);
}
}
componentWillMount = () => {
const event = this.props.displayEvent;
if (event.host._id === this.props.userId)  {
this.setState({ edit: true, joined: false });
} else {
event.users.map((user) => {
if (user._id === this.props.userId) {
return this.setState({joined: true, edit: false});
} else {
return this.setState({join: false, edit: false});
}
});
}
}
render() {
const text = this.state.edit ? "Edit" : this.state.joined ? "Leave" : "Join";
return (
<>   
<button value={text} onClick={this.onClick}>{text}</button>
</>
)
}
}
const stateToProps = (state) => {   
return {
userId: state.user.id
}
}
const mapDispatchToProps = (dispatch) => {
return ({
editEventAssociation: (eventId, users, currentUser, joinedEvent) => dispatch(editEventAssociation(eventId, users, currentUser, joinedEvent))
})
}
const connectedRouterButton = connect(stateToProps, mapDispatchToProps)(EventActionButton);
export default RequireAuth(connectedRouterButton);

以防万一,这就是注销操作。

export const startSignOut = (dispatch) => {
localStorage.removeItem('token');    
localStorage.removeItem('user');
dispatch(removeUser());
dispatch(signOut());
}

其中remove user删除redux存储中的currentUser,signOut从redux存储删除auth令牌。尽管注销使用HOCRequireAuth重定向到/signin页面,但"操作"按钮还是会重新出现。

我不明白EventActionButton的重新渲染是如何触发的?Im未重定向到/上的Landing,Im重定向到/signin

这是有道理的,因为您正在注销,所以从技术上讲,"state.user"中没有"user",所以与其尝试访问"state.user.id",不如将变量分配给"state.uuser",在构造函数中或在任何使用"id"的地方,检查"state.user"是否为NULL,然后分配id。

最新更新