使用createAsyncThunk实现异步Action成功后在组件内重定向的正确方法
实现方案
核心逻辑完全收在组件内部,不耦合路由依赖到异步thunk里,利用createAsyncThunk dispatch后返回的action自带状态标记,精准判断请求结果,只有成功时才触发跳转。
具体改动点
- 从
react-router-dom引入useNavigatehook,在组件内拿到路由跳转能力 - 在提交回调中等待dispatch异步thunk的结果,通过action的状态类型判断是否为成功请求
- 仅匹配到成功状态时,执行
navigate('/tasks')跳转 - 请求出错时,流程自然走到判断分支外,不触发任何跳转逻辑
完整可运行的组件代码
import React from 'react'; import { useSelector, useDispatch } from 'react-redux'; // 引入路由导航能力 import { useNavigate } from 'react-router-dom'; import { RootStateType, AppDispatch} from '../../store'; import { changeTask } from '../../reducers/todo'; import { addTodo } from '../../async-thunks/todo'; import Form from '../../components/form'; import Button from '../../components/button'; import Input from '../../components/input'; const NewTask: React.FC = () => { const dispatch = useDispatch<AppDispatch>(); // 初始化导航函数 const navigate = useNavigate(); const newTask = useSelector((state: RootStateType) => state.todo.newTask); const onTaskAdd = async (event: React.FormEvent<HTMLFormElement>) => { // 阻止表单默认提交导致的页面刷新 event.preventDefault(); const dispatchedAction = await dispatch(addTodo(newTask)); // 仅匹配thunk的成功action时才跳转 if (dispatchedAction.type === 'tasks/addTask/fulfilled') { navigate('/tasks'); } }; const onTaskNameChange = (event: React.ChangeEvent<HTMLInputElement>) => { event.stopPropagation(); dispatch(changeTask(event.target.value)); }; return ( <Form onSubmit={onTaskAdd}> <Input type="text" value={newTask} onChange={onTaskNameChange}></Input> <Button type="submit">Submit</Button> </Form> ); }; export default React.memo(NewTask);
补充说明
- 这种写法不需要额外写全局错误捕获,只要请求失败(不管是网络异常、接口报错、thunk内部抛错),都会触发
tasks/addTask/rejected类型的action,永远不会进入跳转判断分支,完全匹配需求 - 也可以用
unwrap()写法实现等价逻辑,但需要搭配try/catch块捕获失败抛出的异常,否则会出现未捕获的Promise报错,相比之下直接判断action类型的写法侵入性更低:// 等价写法示例 try { await dispatch(addTodo(newTask)).unwrap(); navigate('/tasks'); } catch (err) { // 失败分支,不跳转 } - 整个跳转逻辑全程在组件内部完成,没有把路由相关的依赖传入异步thunk,保证了thunk的可复用性,没有破坏原有代码的结构分层。
内容的提问来源于stack exchange,提问作者malcoauri
相关产品推荐
相关产品推荐

