TypeScript结合Redux使用Dispatch API遇阻,请求技术协助
问题修正方案
核心问题分析
你的代码主要有几个关键错误,导致dispatch无法正常工作:
- React Hooks不能在异步Thunk中使用:
useAppDispatch是React Hook,只能在函数组件或自定义Hook内调用,不能直接放在createAsyncThunk的异步逻辑里。 - API响应数据结构处理错误:Themealdb的API返回的是包含
meals字段的对象,不是直接的字符串数组,你定义的类型和数据提取逻辑都错了。 - 异步逻辑的实现方式不符合Redux Toolkit规范:
createAsyncThunk的正确用法是返回数据,然后通过slice的extraReducers处理异步状态,而非在Thunk内部手动dispatch。 - 类型定义不匹配:
MealState中的meal字段应该是餐品对象数组,不是字符串数组。
修正后的完整代码
1. Redux Slice文件(meal.ts)
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'; import axios from 'axios'; // 定义餐品数据的接口,根据API返回结构补充字段 export interface Meal { idMeal: string; strMeal: string; strMealThumb: string; // 其他需要的字段可自行添加 } export interface MealState { meal: Meal[]; input: string; favorites: string[]; categories: string[]; loading: boolean; // 新增:异步加载状态 error: string | null; // 新增:错误状态 } const initialState: MealState = { meal: [], input: '', favorites: [], categories: [], loading: false, error: null, }; // 正确定义异步Thunk:仅返回数据,由extraReducers处理结果 export const getMeal = createAsyncThunk<Meal[], string>( 'meal/getMeal', async (search: string) => { const response = await axios.get(`https://www.themealdb.com/api/json/v1/1/search.php?s=${search}`); // 处理API返回null的情况(无匹配结果时) return response.data.meals || []; } ); const mealSlice = createSlice({ name: 'meal', initialState, reducers: { addInput: (state, action: PayloadAction<string>) => { state.input = action.payload; }, }, // 处理异步Thunk的三种状态:pending/fulfilled/rejected extraReducers: (builder) => { builder .addCase(getMeal.pending, (state) => { state.loading = true; state.error = null; }) .addCase(getMeal.fulfilled, (state, action: PayloadAction<Meal[]>) => { state.loading = false; state.meal = action.payload; }) .addCase(getMeal.rejected, (state, action) => { state.loading = false; state.error = action.error.message || '获取餐品数据失败'; }); }, }); export default mealSlice.reducer; export const { addInput } = mealSlice.actions;
2. Header组件文件
import { useEffect, useState } from 'react'; import { useAppDispatch, useAppSelector } from '../redux/hooks'; import { getMeal, addInput } from '../redux/meal'; import { RootState } from '../redux/store'; import { Box, TextField } from '@mui/material'; const Header = () => { const dispatch = useAppDispatch(); const input = useAppSelector((state: RootState) => state.meal.input); const [inputText, setInputText] = useState(input); const inputHandler = (e: React.ChangeEvent<HTMLInputElement>) => { setInputText(e.target.value.toLowerCase()); }; useEffect(() => { // 添加防抖,避免输入时频繁触发API请求 const timer = setTimeout(() => { dispatch(getMeal(inputText)); }, 300); dispatch(addInput(inputText)); return () => clearTimeout(timer); }, [dispatch, inputText]); return ( <Box sx={{ m: 3 }}> <TextField onChange={inputHandler} placeholder="Search" sx={{ mb: 3 }} value={inputText} // 设为受控组件,保证输入框值与state同步 /> </Box> ); }; export default Header;
关键修正说明
- 移除了Thunk内部的
useAppDispatch调用,改用Redux Toolkit的extraReducers自动处理异步结果的dispatch。 - 修正了API数据的类型定义和提取逻辑,正确处理无匹配结果时的null值。
- 添加了
loading和error状态,便于处理异步加载过程中的UI反馈。 - 给输入框添加防抖逻辑,减少不必要的API请求。
- 修正了输入框的事件类型,符合TypeScript规范,同时将输入框设为受控组件。
内容的提问来源于stack exchange,提问作者Yohav Rn
相关产品推荐
相关产品推荐

