历史推送后反应路由器不会重新渲染 [英] react router doesn't re-render after history push
问题描述
我希望在用户登录后重新渲染/刷新,所以我使用 history.push
来做到这一点.
import {history} from '../layout/Navbar'export const loginUser = userData =>调度 =>{axios.post('/users/login', userData).then( res => {//从响应中获取令牌const token = res.data.token;//console.log(token);//在会话中传递令牌sessionStorage.setItem("jwtToken", token);//设置授权令牌setAuthToken(令牌);//解码认证令牌const 解码 = jwt_decode(token);//传递解码后的令牌调度(设置当前用户(解码))history.push('/仪表板');}).catch(错误 => {如果(错误.响应.数据){控制台日志(错误响应)派遣({类型:GET_ERRORS,有效载荷:err.response.data})}})}export const getUser = () =>{返回(调度)=>{return axios.get('/users/current_user',{}).then( res => {常量数据 = res.data调度({类型:GET_CURRENT_USER,数据})})}}export const setCurrentUser = (decoded, dispatch) =>{返回{类型:SET_CURRENT_USER,有效载荷:解码,}}
相反,它似乎没有重新渲染,因为我收到一个错误,只有在用户未登录时才会出现错误.
例如
TypeError: 无法读取未定义的属性用户"
在我的一个组件上.
在仪表板页面刷新时,错误消失了,所以我正在寻找一种方法来重新呈现状态,并重定向到仪表板,这样用户就会存在,或者如果给出错误的凭据,则会抛出未经授权的错误.
Navbar.js
import React, {Component} from "react";从react-router-dom"导入 {BrowserRouter, Link, Route, Switch};从 '../components/PrivateRoute' 导入 PrivateRoute;从'../components/Home'导入Home;从../components/Dashboard"导入仪表板;从'react-redux'导入{connect};从'../components/Login'导入登录;从 '@material-ui/core/AppBar' 导入 AppBar;从@material-ui/core/Toolbar"导入工具栏;从@material-ui/core/Typography"导入排版;从@material-ui/core/Button"导入按钮;从'../actions/authActions'导入{logoutUser};从../components/SignUp"导入注册;从@material-ui/core/Grid"导入网格;从历史"导入 {createBrowserHistory};//从 'history/createBrowserHistory' 导入 createBrowserHistory导出 const 历史记录 = createBrowserHistory()类导航栏扩展组件{注销 = (e) =>{e.preventDefault();this.props.logoutUser();}使成为() {//链接const authLinks = (<跨度><按钮><Link to="/dashboard" color="primary">仪表盘</链接></按钮><Button onClick={this.logout} to="/"><span>注销</span></按钮></span>);const 访客链接 = (<跨度><按钮><链接到="/登录">登录</链接></按钮><按钮><链接到="/注册">报名</链接></按钮></span>);返回 (<div><BrowserRouter history={history}><AppBar position="static"><工具栏><Grid justify="space-between" 容器 ><Typography variant="h6" style={{ color: '#fff'}}>图片上传应用</排版>{/* 如果通过身份验证,将呈现 authlinks如果不是将呈现访客链接*/}<网格项目><按钮对齐=右"><Link style={{ color:'#fff'}} underline="none" to="/">家</链接></按钮>{this.props.auth.isAuthenticated ?authLinks : 访客链接}</网格></网格></工具栏></AppBar><开关><路由精确路径="/" component={Home}/><路由精确路径=/signUp"组件={SignUp}/><路由精确路径=/登录"组件={登录}/>{/* 认证用户的私有路由 */}<PrivateRoute 精确路径="/dashboard" component={Dashboard}></PrivateRoute></开关></BrowserRouter>
)}}const mapDispatchToProps = (调度) =>({注销用户:() =>调度(注销用户())})const mapStateToProps = (状态) =>({身份验证:state.auth})导出默认连接(mapStateToProps,mapDispatchToProps)(导航栏)
App.js
import React, { Component } from 'react';导入'./App.css';从./actions/utils/setAuthToken"导入 setAuthToken;从 './layout/Navbar' 导入导航栏;从jwt-decode"导入jwt_decode;从./store"导入商店;从 './actions/authActions' 导入 {setCurrentUser, logoutUser, getUser };从react-redux"导入{提供者};//JWT 代币如果(sessionStorage.jwtToken){//设置身份验证令牌头身份验证setAuthToken(sessionStorage.jwtToken);//解码token,获取用户信息和expconst 解码 = jwt_decode(sessionStorage.jwtToken);//设置用户和 isAuthenticatedstore.dispatch(setCurrentUser(decoded));store.dispatch(getUser());//检查过期令牌const currentTime = Date.now()/1000;if (decoded.exp < currentTime) {//注销用户store.dispatch(logoutUser());//重定向到登录window.location.href = "/登录";}}类 App 扩展组件 {使成为(){返回 (<提供者商店={商店}><导航栏/></提供者>);}}导出默认应用程序;
登录
import React, { Component } from "react";从'react-redux'导入{connect};从react-router-dom"导入{重定向};从 '../actions/authActions' 导入 {loginUser, googleLogin };从@material-ui/core/Grid"导入网格;从prop-types"导入 PropTypes;从react-google-login"导入 { GoogleLogin };从'@material-ui/core/Divider' 导入分频器;从@material-ui/core/Typography"导入排版;从react-social-login-buttons"导入{ GoogleLoginButton};从'./LoginForm/LoginForm'导入登录表单;从'../layout/Navbar'导入{history};import { withRouter } from "react-router-dom";//const onSuccess = response =>控制台日志(响应);//const onFailure = response =>控制台错误(响应);类登录扩展组件{构造函数(){极好的();this.state = {表单数据:{用户名:'',密码:'',isAuthenticated: 假,},错误:{}}}登录Github = (e) =>{e.preventDefault();console.log('你好');this.props.githubLogin();}componentDidMount() {//console.log(this.props.auth);如果(this.props.auth.isAuthenticated){this.props.history.push("/dashboard");}}componentDidUpdate(){如果(this.props.auth.isAuthenticated){this.props.history.push("/dashboard")}}handleChange = (e) =>{e.preventDefault();const {formData} = this.state;this.setState({表单数据:{...表单数据,[e.target.name]: e.target.value}});}handleSubmit = (e) =>{e.preventDefault();const {formData} = this.state;const {用户名,密码} = formData;const 信用 = {用户名,密码}this.props.loginUser(creds, this.props.history);//console.log(creds);}使成为(){const googleLogin = 响应 =>{让谷歌数据;谷歌数据 = {googleID: response.profileObj.googleId,电子邮件:response.profileObj.email,// 密码: "",};控制台日志(谷歌数据);this.props.googleLogin(googleData);};返回(<div><网格容器 justify="center" spatial={0}><网格项 sm={10} md={6} lg={4} style={{ margin:'20px 0px'}}><Typography variant="h4" style={{ letterSpacing: '2px'}} >登入</排版>{this.props.auth.errors ?(this.props.auth.errors.map( (err, i) => (<div key={i} style={{color: 'red' }}>{呃}
))):(空值)}<登录表单mySubmit={this.handleSubmit}myChange={this.handleChange}用户名={this.state.username}密码={this.state.password}/><网格项 sm={12}><Typography align="center" variant="h4" style={{ letterSpacing: '6px'}} >或者</排版><Divider style={{ width: '200px', margin:'20px auto', backgroundColor:'#000000'}} variant="middle"/></网格></网格></网格>
)}}登录.propTypes = {登录用户:PropTypes.func.isRequired,身份验证:PropTypes.object.isRequired,错误:PropTypes.object};const mapStateToProps = (状态) =>({身份验证:state.auth})const mapDispatchToProps = (调度) =>({登录用户:(用户数据)=>调度(登录用户(用户数据)),googleLogin: (userData) =>调度(谷歌登录(用户数据))})导出默认连接(mapStateToProps, mapDispatchToProps)(withRouter(Login))
所以看起来我没有使用导航栏 history
,
so 而不是 this.props.history.push("/dashboard")
我使用了 history.push('/dashboard')
Login.js
.....componentDidMount() {//console.log(this.props.auth);如果(this.props.auth.isAuthenticated){history.push("/仪表板");}}componentDidUpdate(){如果(this.props.auth.isAuthenticated){history.push("/仪表板")}}
Navbar.js
并改变这个
export const history = createBrowserHistory()
到这里
export const history = createBrowserHistory({forceRefresh:true})
这不使用 withRouter()
实例.
我仍然需要从 authActions.js
loginUser
函数中删除 history.push
.
I'm looking to re render/refresh, after a user has logged in, so im using history.push
to do that.
import {history} from '../layout/Navbar'
export const loginUser = userData => dispatch => {
Axios.post('/users/login', userData)
.then( res => {
// retrieve token from the response
const token = res.data.token;
// console.log(token);
// pass the token in session
sessionStorage.setItem("jwtToken", token);
// set the auth token
setAuthToken(token);
// decode the auth token
const decoded = jwt_decode(token);
// pass the decoded token
dispatch(setCurrentUser(decoded))
history.push('/dashboard');
})
.catch(err => {
if(err.response.data){
console.log(err.response)
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
}
})
}
export const getUser = () => {
return (dispatch) => {
return Axios.get('/users/current_user',{
}).then( res => {
const data = res.data
dispatch({type: GET_CURRENT_USER, data})
})
}
}
export const setCurrentUser = (decoded, dispatch) => {
return{
type:SET_CURRENT_USER,
payload:decoded,
}
}
Instead it doesn't seem to re-render because im getting an error that only should have an error if a user isn't logged in.
For example
TypeError: Cannot read property 'user' of undefined
on one of my components.
On refresh on the dashboard page, the error goes away, so im looking for a way to re render the state, and redirect to dashboard that way a user will exist or throw an unauthorized error if given the wrong credentials.
Navbar.js
import React, {Component} from "react";
import {BrowserRouter, Link, Route, Switch} from "react-router-dom";
import PrivateRoute from '../components/PrivateRoute';
import Home from '../components/Home';
import Dashboard from '../components/Dashboard';
import {connect} from 'react-redux';
import Login from '../components/Login';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import {logoutUser} from '../actions/authActions';
import SignUp from "../components/SignUp";
import Grid from '@material-ui/core/Grid';
import {createBrowserHistory} from 'history';
// import createBrowserHistory from 'history/createBrowserHistory'
export const history = createBrowserHistory()
class Navbar extends Component {
logout = (e) => {
e.preventDefault();
this.props.logoutUser();
}
render() {
// LINKS
const authLinks = (
<span>
<Button>
<Link to="/dashboard" color="primary">
Dashboard
</Link>
</Button>
<Button onClick={this.logout} to="/">
<span>Logout</span>
</Button>
</span>
);
const guestLinks = (
<span>
<Button>
<Link to="/login">
Login
</Link>
</Button>
<Button>
<Link to="/signup">
Sign Up
</Link>
</Button>
</span>
);
return (
<div>
<BrowserRouter history={history}>
<AppBar position="static">
<Toolbar>
<Grid justify="space-between" container >
<Typography variant="h6" style={{ color: '#fff'}}>
Image Upload App
</Typography>
{/* if is authenticated, will render authlinks
if not will render guest links
*/}
<Grid item>
<Button align="right">
<Link style={{ color:'#fff'}} underline="none" to="/">
Home
</Link>
</Button>
{this.props.auth.isAuthenticated ? authLinks : guestLinks}
</Grid>
</Grid>
</Toolbar>
</AppBar>
<Switch>
<Route exact path="/" component={Home}/>
<Route exact path="/signUp" component ={SignUp}/>
<Route exact path="/login" component={Login}/> {/* private routes for users who are authenticated */}
<PrivateRoute exact path="/dashboard" component={Dashboard}></PrivateRoute>
</Switch>
</BrowserRouter>
</div>
)
}
}
const mapDispatchToProps = (dispatch) => ({
logoutUser: () => dispatch(logoutUser())
})
const mapStateToProps = (state) => ({
auth: state.auth
})
export default connect(mapStateToProps,mapDispatchToProps)(Navbar)
App.js
import React, { Component } from 'react';
import './App.css';
import setAuthToken from "./actions/utils/setAuthToken";
import Navbar from './layout/Navbar';
import jwt_decode from "jwt-decode";
import store from './store';
import {setCurrentUser, logoutUser, getUser } from './actions/authActions';
import { Provider } from "react-redux";
// JWT TOKEN
if (sessionStorage.jwtToken) {
// Set auth token header auth
setAuthToken(sessionStorage.jwtToken);
// Decode token and get user info and exp
const decoded = jwt_decode(sessionStorage.jwtToken);
// Set user and isAuthenticated
store.dispatch(setCurrentUser(decoded));
store.dispatch( getUser());
// Check for expired token
const currentTime = Date.now() / 1000;
if (decoded.exp < currentTime) {
// Logout user
store.dispatch(logoutUser());
// Redirect to login
window.location.href = "/login";
}
}
class App extends Component {
render(){
return (
<Provider store={store}>
<Navbar/>
</Provider>
);
}
}
export default App;
Login
import React, { Component } from "react";
import {connect} from 'react-redux';
import {Redirect} from "react-router-dom";
import {loginUser, googleLogin } from '../actions/authActions';
import Grid from '@material-ui/core/Grid';
import PropTypes from "prop-types";
import { GoogleLogin } from "react-google-login";
import Divider from '@material-ui/core/Divider';
import Typography from '@material-ui/core/Typography';
import { GoogleLoginButton} from "react-social-login-buttons";
import LoginForm from './LoginForm/LoginForm';
import {history} from '../layout/Navbar';
import { withRouter } from "react-router-dom";
// const onSuccess = response => console.log(response);
// const onFailure = response => console.error(response);
class Login extends Component{
constructor() {
super();
this.state = {
formData:{
username:'',
password:'',
isAuthenticated: false,
},
errors:{}
}
}
logInGithub = (e) => {
e.preventDefault();
console.log('hello');
this.props.githubLogin();
}
componentDidMount() {
// console.log(this.props.auth);
if (this.props.auth.isAuthenticated) {
this.props.history.push("/dashboard");
}
}
componentDidUpdate(){
if(this.props.auth.isAuthenticated){
this.props.history.push("/dashboard")
}
}
handleChange = (e) => {
e.preventDefault();
const {formData} = this.state;
this.setState({
formData: {
...formData,
[e.target.name]: e.target.value
}
});
}
handleSubmit = (e) => {
e.preventDefault();
const {formData} = this.state;
const {username, password} = formData;
const creds = {
username,
password
}
this.props.loginUser(creds, this.props.history);
// console.log(creds);
}
render(){
const googleLogin = response => {
let googleData;
googleData = {
googleID: response.profileObj.googleId,
email: response.profileObj.email,
// password: "",
};
console.log(googleData);
this.props.googleLogin(googleData);
};
return(
<div>
<Grid container justify="center" spacing={0}>
<Grid item sm={10} md={6} lg={4} style={{ margin:'20px 0px'}}>
<Typography variant="h4" style={{ letterSpacing: '2px'}} >
Sign In
</Typography>
{this.props.auth.errors ? (
this.props.auth.errors.map( (err, i) => (
<div key={i} style={{color: 'red' }}>
{err}
</div>
))
):(
null
)}
<LoginForm
mySubmit={this.handleSubmit}
myChange={this.handleChange}
username={this.state.username}
password={this.state.password}
/>
<Grid item sm={12}>
<Typography align="center" variant="h4" style={{ letterSpacing: '6px'}} >
OR
</Typography>
<Divider style={{ width: '200px', margin:'20px auto', backgroundColor:'#000000'}} variant="middle" />
</Grid>
</Grid>
</Grid>
</div>
)
}
}
Login.propTypes = {
loginUser: PropTypes.func.isRequired,
auth: PropTypes.object.isRequired,
errors: PropTypes.object
};
const mapStateToProps = (state) => ({
auth: state.auth
})
const mapDispatchToProps = (dispatch) => ({
loginUser: (userData) => dispatch(loginUser(userData)),
googleLogin: (userData) => dispatch(googleLogin(userData))
})
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(Login))
So it appears that i wasn't using the navbar history
,
so instead of this.props.history.push("/dashboard")
I used history.push('/dashboard')
Login.js
.....
componentDidMount() {
// console.log(this.props.auth);
if (this.props.auth.isAuthenticated) {
history.push("/dashboard");
}
}
componentDidUpdate(){
if(this.props.auth.isAuthenticated){
history.push("/dashboard")
}
}
Navbar.js
and change this
export const history = createBrowserHistory()
to this
export const history = createBrowserHistory({forceRefresh:true})
This is without using withRouter()
instances.
I still had to remove history.push
from the authActions.js
loginUser
function.
这篇关于历史推送后反应路由器不会重新渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!