Я реализую защищенные маршруты в своем приложении React, используя Redux для управления состоянием и React Router для маршрутизации. После успешного входа в систему я могу перейти к защищенным маршрутам. Однако когда я вручную вставляю URL-адрес и пытаюсь перейти к защищенному маршруту (например, video/1245/), меня перенаправляют обратно на страницу входа, даже если я вошел в систему.
Компонент входа:
function Login() {
const navigate = useNavigate();
const dispatch = useDispatch();
const formik = useFormik<formValues>({
initialValues: {
email: '',
password: ''
},
validationSchema: loginValidation,
onSubmit: () => {
axios.post('/login/', {
email: formik.values.email,
password: formik.values.password
}, {
headers: {
'Content-Type': 'application/json'
}
})
.then((response: AxiosResponse) => {
if (response.status === 200) {
toast.success('Login successful');
navigate('/');
dispatch(loginUser(response.data.userStatus));
try {
localStorage.setItem('userInfo', JSON.stringify(response.data));
} catch (error) {
toast.error('Something went wrong');
}
}
})
.catch((error: AxiosError) => {
toast.error(error.response?.data as string);
});
}
});
return (
);
}
export default Login;
Компонент защищенной страницы:
const ProtectedPage: React.FC<ProtectedPageProps> = ({ Component }: ProtectedPageProps) => {
const navigate = useNavigate();
const { isUserLogin } = useSelector((state: RootState) => state.userAuth);
useEffect(() => {
if (!isUserLogin) {
navigate('/login');
}
}, [isUserLogin]);
return <>{isUserLogin ? Component : null}</>;
};
export default ProtectedPage;
Часть аутентификации пользователя
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
export const userAuthSlice = createSlice({
name: 'userAuth',
initialState: {
isUserLogin: false,
userStatus: ''
},
reducers: {
loginUser: (state, action: PayloadAction<string>) => {
state.isUserLogin = true;
state.userStatus = action.payload;
},
logoutUser: (state) => {
localStorage.clear();
state.isUserLogin = false;
state.userStatus = '';
}
}
});
export const { loginUser, logoutUser } = userAuthSlice.actions;
export default userAuthSlice.reducer;
Компонент приложения
function App() {
return (
<>
<Navbar />
<ToastContainer />
<Routes>
<Route path='/' element = {<Landing />} />
<Route path='/login' element = {<Login />} />
<Route path='/signup' element = {<Signup />} />
<Route path='/verification' element = {<Verification />} />
<Route path='/verification-request' element = {<VerificationRequest />} />
<Route path='/password-reset-request' element = {<PasswordResetRequest />} />
<Route path='/reset-password' element = {<ResetPassword />} />
<Route path='/password-reset-verify' element = {<PasswordResetVerify />} />
<Route path='/upload-video' element = {<UploadVideo />} />
<Route path='/videos/' element = {<ProtectedPage Component = {<Videos />} />} />
<Route path='/video/:videoId' element = {<ProtectedPage Component = {<RetriveVideo />} />} />
</Routes>
</>
);
}
export default App;
Проблема: Когда я вручную перехожу к защищенному маршруту после входа в систему, я перенаправляюсь на страницу входа вместо доступа к защищенному маршруту.
Что я пробовал:
🤔 А знаете ли вы, что...
React имеет строгую систему типов с использованием TypeScript или Flow.
Проблема в том, что состояние избыточности не является постоянным: если вы вручную загрузите защищенную страницу, она прочитает исходное состояние, которое вы настроили при создании среза.
Таким образом, решением было бы использовать localStorage
вместо просто false
в свойстве isUserLogin
. Теперь только после входа в систему localStorage
будет иметь это значение, поэтому проверка будет постоянной на всех вкладках.
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
export const userAuthSlice = createSlice({
name: 'userAuth',
initialState: {
isUserLogin: Boolean(window.localStorage.getItem('userInfo')), //HERE
userStatus: ''
},
reducers: {
loginUser: (state, action: PayloadAction<string>) => {
state.isUserLogin = true;
state.userStatus = action.payload;
},
logoutUser: (state) => {
localStorage.clear();
state.isUserLogin = false;
state.userStatus = '';
}
}
});
export const { loginUser, logoutUser } = userAuthSlice.actions;
export default userAuthSlice.reducer;