背景
我有一个使用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。