我在做受保护的路由.我使用REDUX和纯react 应用程序和react 路由DOM.问题是,当我转到/profile/edit
并点击刷新时,它会将我重定向到/login
&>/profile
.我创建了一条受保护的路由.我想做一些东西,当我在isAuthenticated
页的时候,它会留在那一页上.我不想让它把我转到/profile
.我把我的protectedRoute
投进了element
,结果出了问题.现在我在loader
号楼里面用.但现在我的protected route
坏了.有人能告诉我怎么才能做到这一点吗?或者给我任何 idea ?谢谢
// App.js
<Routes>
<Route
element={
<ProtectedRoute
isAuthenticatedRoute={false}
sendTo={"/profile"}
/>
}
>
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
</Route>
{/* Profile Pages */}
<Route
element={
<ProtectedRoute
isAuthenticatedRoute={true}
sendTo={"/login"}
/>
}
>
<Route path="/profile" element={<Profile />} />
<Route path="/profile/category" element={<EditCategory />} />
<Route path="/profile/edit" element={<EditProfile />} />
</Route>
{/* Page Not Found */}
<Route path="/*" element={<PageNotFound />} />
</Routes>
// App.js with loader
<Routes>
<Route
loader={
<ProtectedRoute
isAuthenticatedRoute={false}
sendTo={"/profile"}
/>
}
>
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
</Route>
</Routes>
// ProtectedRoutes.js
import React, { useEffect } from "react";
import { useSelector } from "react-redux";
import { Navigate, Outlet, useNavigate } from "react-router-dom";
import AppLoader from "../AllLoader/AppLoader/AppLoader";
import { useLoadUserQuery } from "../../redux/feature/apiSlice/apiSlice";
const ProtectedRoute = ({
isAuthenticatedRoute,
children,
adminRoute,
isAdmin,
sendTo,
}) => {
const navigate = useNavigate();
const { isLoading } = useLoadUserQuery(undefined, undefined);
const { user } = useSelector((state) => state.auth);
if (isLoading) {
return <AppLoader />;
}
const isAuthenticated = user;
if (isAuthenticatedRoute && !isAuthenticated) {
return <Navigate to="/login" replace={true} />;
}
if (!isAuthenticatedRoute && isAuthenticated) {
return <Navigate to="/profile" replace={true} />;
}
return children ? children : <Outlet />;
};
export default ProtectedRoute;
My redux store
import { configureStore } from "@reduxjs/toolkit";
import newsSliceReducer from "./feature/newsSlice/newsSlice";
import authSliceReducer from "./feature/userSlice/authSlice";
import profileSliceReducer from "./feature/profileSlice/profileSlice";
import languageSliceReducer from "./feature/languageSlice/languageSlice";
import otherSliceReducer from "./feature/otherSlice/otherSlice";
import { apiSlice } from "./feature/apiSlice/apiSlice";
import { getUserProfile, refreshToken } from "./feature/userSlice/authApi";
const store = configureStore({
reducer: {
[apiSlice.reducerPath]: apiSlice.reducer,
// For Getting all news
allNews: newsSliceReducer,
// For Authorization
auth: authSliceReducer,
// For user Profile
profile: profileSliceReducer,
// For others Data
other: otherSliceReducer,
// For Langauge which will be used later
languages: languageSliceReducer,
},
// devTools: false,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(apiSlice.middleware),
});
// Here will call the Get profile and refresh topke
const initializeApp = async () => {
await store.dispatch(
apiSlice.endpoints.refreshToken.initiate({}, { forceRefetch: true })
);
await store.dispatch(
apiSlice.endpoints.loadUser.initiate({}, { forceRefetch: true })
);
// await store.dispatch(refreshToken());
// await store.dispatch(getUserProfile());
};
initializeApp();
export default store;
//apiSlice
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { SERVER } from "../../../utils/backend";
import { userValue } from "../userSlice/authSlice";
export const apiSlice = createApi({
reducerPath: "api",
baseQuery: fetchBaseQuery({ baseUrl: SERVER }),
endpoints: (builder) => ({
refreshToken: builder.query({
query: (data) => ({
url: "/user/refresh-token",
method: "GET",
credentials: "include",
}),
}),
// Load users
loadUser: builder.query({
query: (data) => ({
url: "/user/me",
method: "GET",
credentials: "include",
}),
async onQueryStarted(arg, { queryFulfilled, dispatch }) {
try {
const result = await queryFulfilled;
dispatch(
userValue({
token: result.data.accessToken,
user: result.data.user,
})
);
} catch (error) {
console.log(error.message);
}
},
}),
}),
});
export const { useRefreshTokenQuery, useLoadUserQuery } = apiSlice;
My ApiSlice
import { createSlice } from "@reduxjs/toolkit";
import {
activateUser,
getUserProfile,
refreshToken,
userLogin,
userLogout,
userRegister,
} from "./authApi";
const userSlice = createSlice({
name: "user",
initialState: {
authLoading: false,
getUserProfileLoading: false,
refreshTokenLoading: false,
user: null,
userActivationToken: "",
authError: null,
authMessage: null,
getUserProfileMessage: null,
getUserProfileError: null,
},
reducers: {
clearAuthMessage: (state) => {
state.authMessage = null;
},
clearAuthError: (state) => {
state.authError = null;
},
clearUserProfileError: (state) => {
state.getUserProfileError = null;
},
userValue: (state, action) => {
state.user = action.payload.user;
},
},
extraReducers: (builder) => {
// Register
builder.addCase(userRegister.pending, (state) => {
state.authLoading = true;
});
builder.addCase(userRegister.fulfilled, (state, action) => {
state.authLoading = false;
state.authMessage = action.payload.message;
state.userActivationToken = action.payload.activationToken;
});
builder.addCase(userRegister.rejected, (state, action) => {
state.authLoading = false;
state.authError = action.payload.message;
});
// Login
builder.addCase(userLogin.pending, (state) => {
state.authLoading = true;
});
builder.addCase(userLogin.fulfilled, (state, action) => {
state.authLoading = false;
state.user = action.payload.user;
state.authMessage = action.payload.message;
});
builder.addCase(userLogin.rejected, (state, action) => {
state.authLoading = false;
state.authError = action.payload.message;
});
// Logout =================================================================
builder.addCase(userLogout.pending, (state) => {
state.authLoading = true;
});
builder.addCase(userLogout.fulfilled, (state, action) => {
state.authLoading = false;
state.user = null;
state.authMessage = action.payload.message;
});
builder.addCase(userLogout.rejected, (state, action) => {
state.authLoading = false;
state.authError = action.payload.message;
});
// ========================= Active User ========================================
builder.addCase(activateUser.pending, (state) => {
state.authLoading = true;
});
builder.addCase(activateUser.fulfilled, (state, action) => {
state.authLoading = false;
state.authMessage = action.payload.message;
});
builder.addCase(activateUser.rejected, (state, action) => {
state.authLoading = false;
state.authError = action.payload.message;
});
// ========================= Refresh token ========================================
builder.addCase(refreshToken.pending, (state) => {
state.refreshTokenLoading = true;
});
builder.addCase(refreshToken.fulfilled, (state) => {
state.refreshTokenLoading = false;
});
builder.addCase(refreshToken.rejected, (state) => {
state.refreshTokenLoading = false;
});
//======================================== Get User Profile ========================================
builder.addCase(getUserProfile.pending, (state) => {
state.getUserProfileLoading = true;
});
builder.addCase(getUserProfile.fulfilled, (state, action) => {
state.getUserProfileLoading = false;
state.user = action.payload.user;
});
builder.addCase(getUserProfile.rejected, (state, action) => {
state.getUserProfileLoading = false;
state.getUserProfileError = action.payload.message;
});
},
});
export const {
clearAuthMessage,
clearAuthError,
clearUserProfileError,
userValue,
} = userSlice.actions;
export default userSlice.reducer;
My index.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";
import "./index.css";
import { Provider } from "react-redux";
import store from "./redux/store";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
</React.StrictMode>
);
reportWebVitals();
我期待当我在任何authenticated页,它会留在那里.它不会在第一个/login
&>/profile
页重定向我