我在使用 PrivateRoute
进行身份验证时遇到问题。
由于我使用 redux 来捕获用户的身份验证,因此在呈现组件之前我需要等待 state
从商店返回。
如果没有,页面将自动重定向到 login route
。
我的问题是当前路由会在等待认证结果时重定向到登录页面。验证通过后返回页面。
所以我想先等待 authentication result
。如果通过身份验证,将加载页面组件,否则将重定向到登录页面。
这是我的带有身份验证的私有路由。
import React from "react";
import { Route, Redirect} from "react-router-dom";
import { connect } from "react-redux";
const PrivateRoute = ({ component: Component, auth, role, ...rest }) => {
return (
<Route
{...rest}
render={props => auth.isAuthenticated ? (
<Component {...props} />
) : (
<Redirect to={{
pathname: "/",
state: { from: props.location }
}} />
)
}
/>
)
}
const stateStoreToProp = state => ({
auth: state.loginReducer,
});
export default connect(stateStoreToProp)(PrivateRoute);
这是我的自动重定向登录组件。
let history = useHistory();
let location = useLocation();
let { from } = location.state || { from: { pathname: "/choose" } };
const isAuthenticated = prop.loginReducer.isAuthenticated;
const user = prop.loginReducer.user;
if (isAuthenticated && typeof user !== "undefined") {
history.replace(from);
}
这里是 App.js
import { loadUser } from './actions/AuthAction';
function App() {
useEffect(() => {
store.dispatch(loadUser());
}, []);
return (
<Provider store={store}>
<Router>
<Fragment>
<div className="blockcontain">
<div className="fss">
<div className="rightSide">
<Switch>
<Route path='/' exact component={Login} />
<PrivateRoute exact path='/choose' component={Choose} />
</Switch>
</div>
</div>
</div>
</Fragment>
</Router>
</Provider>
);
}
和 LoginReducer
import {
LOGIN_SUCCESS, LOGIN_FAIL, USER_LOADED, AUTH_ERROR
} from '../actions/typeName';
import Cookies from 'js-cookie';
const initialState = {
token: Cookies.get('token'),
isAuthenticated: null,
loading: true,
user: null
}
const loginReducer = (state = initialState, action) => {
const {type, payload} = action;
switch(type) {
case USER_LOADED:
return {
...state,
isAuthenticated: true,
loading: false,
user: payload
};
case LOGIN_SUCCESS:
Cookies.set('token', payload.access_token, { expires: payload.expires_at });
return {
...state,
isAuthenticated: true,
loading: false
}
case AUTH_ERROR:
case LOGIN_FAIL:
return {
...state,
token:null,
isAuthenticated: false,
loading: true
}
default:
return state;
}
}
export default loginReducer;
我去choose page
,它会去登录页面,因为store for authentication
没有准备好。
谢谢。
答案 0 :(得分:1)
你可以在你的状态中添加一个加载属性,并且只在获取完成时显示路由:
const PrivateRoute = ({ component: Component, auth, isLoading, role, ...rest }) => {
if(isLoading) return <div>Loading...</div>;
return (
<Route
{...rest}
render={(props) =>
auth.isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: '/',
state: { from: props.location },
}}
/>
)
}
/>
)
}
const stateStoreToProp = (state) => ({
isLoading: state.loading,
auth: state.loginReducer,
})
export default connect(stateStoreToProp)(PrivateRoute)
并在你的减速器中添加加载突变,例如:
case REQUEST_LOGIN:
return [...state, isLoading: true];
case LOGIN_SUCCESSFUL:
return [...state, auth: isAuthenticated, isLoading: false];
答案 1 :(得分:1)
您可以做的是在您的身份验证状态中添加一个“加载”密钥,因此在进行身份验证时,状态将为“真”,否则为“假”。如果是真的,你会显示一个加载器。
import React from "react";
import { Route, Redirect} from "react-router-dom";
import { connect } from "react-redux";
const PrivateRoute = ({ component: Component, auth, role, ...rest }) => {
return (
<>
{
auth.loading && (
<Loader/>
)
}
{
!auth.loading && (
(
<Route
{...rest}
render={props => auth.isAuthenticated ? (
<Component {...props} />
) : (
<Redirect to={{
pathname: "/",
state: { from: props.location }
}} />
)
}
/>
)
)
}
</>
)
}
const stateStoreToProp = state => ({
auth: state.loginReducer,
});
export default connect(stateStoreToProp)(PrivateRoute);