I am writing a small application with registration and authorization logic. I managed to register. If successful, I fill in all the states as it should be, and if something goes wrong, I get the isError = true status and the error text itself.
The problem is that I want to redirect the user to another page ONLY IF the registration is successful.
I use: React + TS + Redux-toolkit with createAsyncThunc + react-router-dom
react-hook-form + Zod
My register component
import clsx from 'clsx'
import { FC } from 'react'
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { useNavigate } from 'react-router-dom'
import { useAppDispatch, useAppSelector } from '../../store/hooks'
import { registerUser } from '../../store/slices/userSlice'
import { FormInput } from '../../components/FormInput/FormInput'
import { Button } from '@gravity-ui/uikit'
import { registerSchema, TRegisterSchema } from '../../models/AuthSchema'
import styles from './RegisterForm.module.sass'
interface AuthFormProps {
className?: string
}
export const RegisterForm: FC<AuthFormProps> = ({ className }) => {
const dispatch = useAppDispatch()
const { errorText } = useAppSelector((state) => state.userSlice)
const navigate = useNavigate()
const {
register,
handleSubmit,
formState: { errors },
reset,
} = useForm<TRegisterSchema>({
resolver: zodResolver(registerSchema),
})
const onSubmit = async (data: TRegisterSchema) => {
dispatch(registerUser(data))
reset()
}
return (
<div className={clsx(className, styles.wrapper)}>
<form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
<FormInput
title='Email'
register={register}
registerName='email'
errorText={errors.email?.message}
isErorr={!!errors.email}
/>
<FormInput
title='Name'
register={register}
registerName='name'
errorText={errors.name?.message}
isErorr={!!errors.name}
/>
<FormInput
title='Password'
register={register}
registerName='password'
errorText={errors.password?.message}
isErorr={!!errors.password}
/>
<Button type='submit' className={styles.button} size='xl'>
Register
</Button>
</form>
</div>
)
}
My slice with async thunk
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import UserService from '../../api/Services/UserService'
import { AxiosError } from 'axios'
interface IInitialState {
user: {
accessToken: string
email: string
name: string
}
isError: boolean
errorText: string
isLoading: boolean
}
interface IAuthInfo {
name: string
email: string
password: string
}
export const registerUser = createAsyncThunk(
'user/register',
async (data: IAuthInfo, { rejectWithValue }) => {
try {
const response = await UserService.register(
data.email,
data.password,
data.name
)
return response
} catch (error: AxiosError | unknown) {
if (error instanceof AxiosError) {
return rejectWithValue(error.response?.data)
}
}
}
)
const initialState: IInitialState = {
user: {
accessToken: '',
email: '',
name: '',
},
errorText: '',
isError: false,
isLoading: false,
}
export const userSlice = createSlice({
name: 'general',
initialState,
reducers: {},
extraReducers: (builder) => {
builder.addCase(registerUser.pending, (state) => {
state.isLoading = true
state.errorText = ''
state.isError = false
})
builder.addCase(registerUser.fulfilled, (state, action) => {
if (action.payload) {
state.user.accessToken = action.payload?.accessToken
state.user.email = action.payload.user?.email
state.user.name = action.payload.user?.name
state.errorText = ''
state.isError = false
state.isLoading = false
localStorage.setItem('token', action.payload?.accessToken)
}
})
builder.addCase(registerUser.rejected, (state, action) => {
state.errorText = action.payload as string
state.isError = true
state.isLoading = false
})
},
})
export default userSlice.reducer
I tried to pull the isError state from redux and check it, that is, if isError = false, then redirect to another page, but the problem is that isError is false by default and this check loses its significance.
I'll repeat the question again. How do I make the redirect happen ONLY upon successful registration?
I will be glad of any advice on the topic and without. Thank you all!
registerUser
is an asynchronous action, it returns a Promise that can be awaited in the calling code before calling any additional logic. Surround the action logic in a try/catch
and unwrap the fulfilled/rejected result.
Example:
const onSubmit = async (data: TRegisterSchema) => {
try {
await dispatch(registerUser(data)).unwrap();
// Redirect upon successful registration
navigate(/* target path */, { replace: true });
} catch(error) {
// Registration failure
// handle or ignore error/rejection
} finally {
reset();
}
}
For details see: Handling Thunk Results