You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Redux Toolkit注册成功后如何实现定向跳转?

如何在React+Redux Toolkit注册成功后仅执行页面跳转?

问题背景

我正在开发一个包含注册与授权逻辑的小型应用,已实现注册功能:注册成功时会正确更新所有状态,失败时会将isError设为true并获取错误文本。目前的问题是,我希望仅在注册成功时才将用户重定向到其他页面。

技术栈:React + TypeScript + Redux Toolkit(含createAsyncThunk)+ react-router-dom + react-hook-form + Zod

注册组件代码

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>
    )
}

Redux Slice代码(含createAsyncThunk)

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

我曾尝试通过Redux的isError状态判断跳转,但isError默认值为false,导致页面一加载就触发跳转,无法满足需求。


解决方案

方法一:利用dispatch返回的Promise(推荐)

createAsyncThunk返回的action被dispatch后,会返回一个Promise,通过unwrap()方法可以直接获取thunk的成功结果或捕获错误。在组件的onSubmit函数里处理成功后的跳转逻辑:

修改注册组件中的onSubmit函数:

const onSubmit = async (data: TRegisterSchema) => {
  try {
    // 等待thunk执行完成并获取成功结果
    await dispatch(registerUser(data)).unwrap();
    reset();
    // 注册成功后跳转
    navigate('/dashboard'); // 替换为你的目标路径
  } catch (err) {
    // 注册失败时无需额外操作,因为slice已经更新了错误状态
    console.error('注册失败:', err);
  }
};

原理:unwrap()会提取thunk成功时返回的值,如果thunk被rejectWithValue拒绝,则会抛出对应的错误,这样我们就能精准区分注册成功/失败的场景,仅在成功时执行跳转。


方法二:监听Redux状态变化

通过useEffect监听注册成功后的状态变化(比如user.accessToken从空变为非空),触发跳转:

在注册组件中添加以下代码:

const { user, isLoading, isError } = useAppSelector((state) => state.userSlice);
const navigate = useNavigate();

useEffect(() => {
  // 仅当accessToken存在、非加载状态、无错误时跳转
  if (user.accessToken && !isLoading && !isError) {
    navigate('/dashboard');
    // 可选:跳转后重置表单或状态,避免刷新页面重复跳转
    reset();
  }
}, [user.accessToken, isLoading, isError, navigate, reset]);

注意:如果用户刷新页面,localStorage中的token会保留,可能导致页面再次跳转。可以在slice中添加一个重置状态的reducer,或者在跳转后清除相关状态(根据业务需求调整)。


方法三:不推荐:在Slice中直接跳转

虽然可以在registerUser.fulfilled回调中调用navigate,但不建议这么做——Redux Slice应该保持纯函数,不依赖路由等外部API,否则会降低代码的可维护性和可测试性。


内容的提问来源于stack exchange,提问作者Akaev Dzhalal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 05:14:52