英文:
Navigate on button click using protected routes in react
问题
以下是您提供的代码的中文翻译:
App.js
<Router>
<Routes>
<Route element={<AnonymousUserRoute />}>
<Route path='/user/login' element={<UserLoginScreen />}/>
</Route>
<Route element={<ProtectedUserRoute />} >
<Route path='/' element={<HomeScreen />} exact />
</Route>
</Routes>
</Router>
ProtectedUserRoute.js
function ProtectedUserRoute() {
const loginPageLink = "/user/login";
const token = //从本地存储获取
return (
token ? <Outlet /> : <Navigate to={loginPageLink} replace />
);
};
AnonymousUserRoute.js
function AnonymousUserRoute() {
const homePageLink = "/";
const token = //从本地存储获取
return (
token ? <Navigate to={homePageLink} replace /> : <Outlet />
);
};
Login.js
function UserLoginScreen() {
...
const handleLoginClick = (event) => {
event.preventDefault();
dispatch(loginUser(email, password));
navigate('/');
}
...
}
reducers.js
export const userLoginReducer = (state = { userDetails: { isLoggedIn: false } }, action) => {
switch(action.type) {
case USER_LOGIN_REQUEST:
return { loading: true }
case USER_LOGIN_SUCCESS:
return { loading: false, isLoggedIn: action.payload }
case USER_LOGIN_FAIL:
return { loading: false, error: action.payload }
default:
return state
}
}
actions.js
export const loginUser = (email, password) => async (dispatch) => {
const loginUrl = //登录URL
try {
dispatch({ type: USER_LOGIN_REQUEST })
const loginData = { email: email, password: password }
const config = { headers: { 'Content-type': 'application/json'} }
const { data } = await axios.post(loginUrl, loginData, config)
dispatch({ type: USER_LOGIN_SUCCESS, payload: true })
storeUserLoggedInDetailsInLocalStorage(data.tokens); //调用一个将数据存储在本地存储中的函数。这里没有其他操作。
} catch(error) {
dispatch({
type: USER_LOGIN_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message
})
console.log(error)
}
}
store.js
const userDetailsFromStorage = localStorage.getItem('userDetails') ?
JSON.parse(localStorage.getItem('userDetails')) : {}
const reducer = combineReducers({
userDetails: userLoginReducer,
})
const persistedState = {
userDetails: {
isLoggedIn: userDetailsFromStorage.isLoggedIn ?? false
}
}
const middleWare = [thunk]
const store = createStore(reducer, persistedState, composeWithDevTools(applyMiddleware(...middleWare)));
export default store
希望这些翻译有帮助。如果您有任何其他问题,请随时提问。
英文:
I have App.js
which looks like this
<Router>
<Routes>
<Route element={<AnonymousUserRoute />}>
<Route path='/user/login' element={<UserLoginScreen />}/>
</Route>
<Route element={<ProtectedUserRoute />} >
<Route path='/' element={<HomeScreen />} exact />
</Route>
</Routes>
</Router>
ProtectedUserRoute.js
function ProtectedUserRoute() {
const loginPageLink = "/user/login";
const token = //getting from local storage
return (
token ? <Outlet /> : <Navigate to={loginPageLink} replace />
);
};
AnonymousUserRoute.js
function AnonymousUserRoute() {
const homePageLink = "/";
const token = //getting from local storage
return (
token ? <Navigate to={homePageLink} replace /> : <Outlet />
);
};
Login.js
function UserLoginScreen() {
...
const handleLoginClick = (event) => {
event.preventDefault();
dispatch(loginUser(email, password));
navigate('/');
}
...
}
The problem I am facing is that, once handleLoginClick
is clicked, the navigate
function is not redirecting me to home screen immediately because ProtectedUserRoute
doesn't allow i think. But upon refreshing the page, my route identifies that there is a token in local storage and redirects to home screen. How can i ensure, navigation happens without refresh here ?
EDIT
reducers.js
export const userLoginReducer = (state = { userDetails: { isLoggedIn: false } }, action) => {
switch(action.type) {
case USER_LOGIN_REQUEST:
return { loading: true }
case USER_LOGIN_SUCCESS:
return { loading: false, isLoggedIn: action.payload }
case USER_LOGIN_FAIL:
return { loading: false, error: action.payload }
default:
return state
}
}
actions.js
export const loginUser = (email, password) => async (dispatch) => {
const loginUrl = //loginUrl
try {
dispatch({ type: USER_LOGIN_REQUEST })
const loginData = { email: email, password: password }
const config = { headers: { 'Content-type': 'application/json'} }
const { data } = await axios.post(loginUrl, loginData, config)
dispatch({ type: USER_LOGIN_SUCCESS, payload: true })
storeUserLoggedInDetailsInLocalStorage(data.tokens); //calling a function which stores in localstorage. Nothing else done here.
} catch(error) {
dispatch({
type: USER_LOGIN_FAIL,
payload: error.response && error.response.data.detail
? error.response.data.detail
: error.message
})
console.log(error)
}
}
I have this isLoggedIn
boolean value in Login
screen which will be set to true
once user is logged in. Below is the snippet
const userDetails = useSelector(state => state.userDetails)
const { isLoggedIn } = userDetails
EDIT 2:
store.js
const userDetailsFromStorage = localStorage.getItem('userDetails') ?
JSON.parse(localStorage.getItem('userDetails')) : {}
const reducer = combineReducers({
userDetails: userLoginReducer,
})
const persistedState = {
userDetails: {
isLoggedIn: userDetailsFromStorage.isLoggedIn ?? false
}
}
const middleWare = [thunk]
const store = createStore(reducer, persistedState, composeWithDevTools(applyMiddleware(...middleWare)));
export default store
答案1
得分: 1
loginUser
是一个异步操作,您应该能够使用await
来等待它的解析/拒绝。
类似以下示例:
function UserLoginScreen() {
...
const handleLoginClick = async (event) => {
event.preventDefault();
try {
await dispatch(loginUser(email, password));
navigate('/');
} catch(error) {
// 处理或忽略错误/拒绝
}
}
...
}
演示
loginUser
操作可能需要重新抛出它捕获的任何错误,以便等待的UI可以在UI中捕获并处理它,例如,如果您想要设置一些本地错误状态或触发一个面向用户的提示消息。
英文:
loginUser
is an asynchronous action and you should be able to await
it to resolve/reject.
Something similar to the following example:
function UserLoginScreen() {
...
const handleLoginClick = async (event) => {
event.preventDefault();
try {
await dispatch(loginUser(email, password));
navigate('/');
} catch(error) {
// handle or ignore errors/rejections
}
}
...
}
Demo
The loginUser
action may need to re-throw any errors it catches so UI that is waiting can catch and handle it in the UI, for example if you wanted to set some local error state or trigger a toast message to the user.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论