我正在尝试在我正在从事的项目上实施私有,受保护和公共路线。每次刷新页面时,我都会在app.js的componentDidMount内部调度我的setUserAsync()操作创建者,该调用者会调用后端,以基于登录或注册时分配的令牌询问用户信息。 SetUserAsync设置用户,并在收到用户后将名为isAuthenticated的状态切换为true。然后,我使用isAuthenticated状态来确定要在我的私有和公共路由中呈现或重定向到的组件。
但是我面临的问题是,每当我尝试访问任何私有或受保护的路由时,都会基于isAuthenticated的初始状态false来立即触发三元运算符。因此,在像/ dashboard这样的专用路线上,它将带我进入/ signin,因为isAuthenticated最初为false,直到由app.js的componentDidMount中的setUserAsync()设置为true为止。然后从/ signin重定向到/ dashboard,因为/ signin是受保护的路由,并在isAuthenticated最终变为true时将我带回到/ dashboard。
如何做到这一点,以便刷新时的路由在呈现任何内容之前等待API调用完成。我已经看到许多人正在实施相同的流程,这对他们来说很好,但是我不知道我在做什么错。
//App.js
class App extends React.Component {
componentDidMount() {
const { setUserAsync, token, tokenExpiry } = this.props;
token ? setUserAsync(token) : null
}
render() {
return (
<Switch>
<PublicRoute exact path="/" component={Home} />
<PublicRoute exact path="/about-us" component={AboutUs} />
<PublicRoute exact path="/contact-us" component={ContactUs} />
<PublicRoute exact path="/privacy-policy" component={PrivacyPolicy} />
<PublicRoute exact path="/terms-of-use" component={TermsOfUse} />
<ProtectedRoute exact path="/signin" component={SignIn} />
<ProtectedRoute exact path="/signup" component={SignUp} />
<PrivateRoute exact path="/dashboard" component={Dashboard} />
<PrivateRoute exact path="/all-leads" component={AllLeads} />
</Switch>
)};
const mapStateToProps = createStructuredSelector({
token: selectUserToken,
tokenexpiry: selectTokenExpiry
});
const mapDispatchToProps = dispatch => ({
setUserAsync: (token) => dispatch(setUserAsync(token))
});
export default connect(mapStateToProps, mapDispatchToProps)(App);
//PrivateRoute - dashboard
const PrivateRoute = ({ component: Component,isAuthenticated, ...rest }) => {
return (
<Route
{...rest}
render={props =>
isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{ pathname: "/signin", state: { from: props.location } }}
/>
)
}
/>
)
};
const mapStateToProps = createStructuredSelector({
isAuthenticated: selectIsUserAuthenticated,
});
export default connect(mapStateToProps)(PrivateRoute);
//ProtectedRoute - signin & signup
const ProtectedRoute = ({component: Component, isAuthenticated, isFetching, ...rest}) => {
return !isFetching ? (
<Route
{...rest}
render={(props) =>
isAuthenticated
? <Redirect to={{pathname: '/dashboard', state: {from: props.location}}} />
: <Component {...props} /> }
/>
)
: null
}
const mapStateToProps = createStructuredSelector({
isAuthenticated: selectIsUserAuthenticated,
isFetching: selectIsFetching
});
export default connect(mapStateToProps)(ProtectedRoute);
//User reducer
const INITIAL_STATE = {
isAuthenticated: false,
currentUser: null
};
const UserReducer = (state = INITIAL_STATE, action) => {
const { type, payload } = action;
switch (type) {
case UserActionTypes.FETCH_USER_SUCCESS: {
return {
...state,
isAuthenticated: true,
currentUser: payload
};
}
case UserActionTypes.FETCH_USER_ERROR: {
return {
...state,
isAuthenticated: false,
currentUser: null
};
}
default:
return state;
}
};
export default UserReducer;
答案 0 :(得分:0)
您使用哪种身份验证?
如果您使用JWT并将令牌存储在localStorage中,则可以执行以下操作:
const isAuthorized = isLoggedIn || localStorage.get('token');
/* isLoggedIn - user has just logged in with Login Page,
localStorage.get('token') - user refreshed page and he has a token,
you don't want to redirect him until token fails */
因此,您认为具有令牌的用户已被授权,但是他看不到任何后端数据,因为他必须提取该数据。
如果他的令牌无效,后端将返回401响应,您将清除用户令牌并将其重定向到登录。
您还可以使用两个Switch块。
const renderPrivateRoute = (item, index) => (
<PrivateRoute key={index} {...item} />
);
const renderPublicRoute = (item, index) => (
<PublicRoute key={index} {...item} />
);
/* ... */
{
isAuthorized ?
(<Switch>
{privateRoutes.map(renderPrivateRoute)}
<Route
path="*"
render={() => <Redirect to={{ pathname: DEFAULT_PRIVATE_ROUTE }} />}
/>
</Switch>) :
(<Switch>
{publicRoutes.map(renderPublicRoute)}
<Route
path="*"
render={() => <Redirect to={{ pathname: DEFAULT_PUBLIC_ROUTE }} />}
/>
</Switch>)
}
使用React Suspense的第二种方法,但仍处于试验阶段。您也可以尝试自己做类似的事情。 https://reactjs.org/docs/concurrent-mode-suspense.html
第三种方法是持久存储。
看看redux-persist
npm软件包。