React Native+Redux Toolkit异步API调用类型及Hook调用错误
问题解决方案
错误1:类型错误 AsyncThunkAction<any, void, AsyncThunkConfig> 无法赋值给 AnyAction
原因
react-redux 原生的 useDispatch() 返回的是 Dispatch<AnyAction> 类型,而 createAsyncThunk 生成的异步 action 属于 AsyncThunkAction 类型,两者类型不兼容。
解决方法
使用你在 hooks.ts 中定义的自定义类型化钩子 useAppDispatch,替换原生的 useDispatch。
错误2:无效钩子调用 Invalid hook call. Hooks can only be called inside of the body of a function component
原因
你在 splash.tsx 中混用了原生钩子和自定义类型化钩子,导致类型和调用逻辑冲突(虽然你的钩子调用位置符合规则,但类型不匹配会间接引发此类错误提示)。
解决方法
统一使用 hooks.ts 导出的 useAppSelector 和 useAppDispatch,替换原生的 useSelector/useDispatch。
修改后关键代码
1. 更新 splash.tsx
import React from "react"; import { View, TouchableOpacity, Text, SafeAreaView, Image } from "react-native"; import { styles } from "../../utility/styles/styles"; import { selectStatus } from "../../slices/todo/todoSlice"; // 替换原生钩子为自定义类型化钩子 import { useAppSelector, useAppDispatch } from "../../hooks/hooks"; import { getHomeData } from "../../actions/get_home_json"; function Splash({ navigation}: {navigation : any}) { // 使用自定义钩子 const status = useAppSelector(selectStatus); const dispatch = useAppDispatch(); const handleClick = () => {dispatch(getHomeData())}; return ( <SafeAreaView> <View > <Image source={require('../../resources/images/gif/splash.gif')} style={styles.image} /> <TouchableOpacity style={styles.button} onPress={handleClick}> <Text> Push Home</Text> </TouchableOpacity> </View> </SafeAreaView> ); }; export default Splash;
2. 补充 todoSlice.ts 的异步 action 处理
你当前的切片只处理了 fetchTodos,需要添加 getHomeData 的状态更新逻辑:
// todoSlice.ts import {Todo} from "../../models/todo" import { RootState } from "../../store/store"; import { createSlice } from "@reduxjs/toolkit"; import { fetchTodos } from "../../actions/fetchTodos"; import { getHomeData } from "../../actions/get_home_json"; // 扩展状态类型,添加首页数据字段 type TodosState = { status: "loading" | "idle"; error: string | null; list: Todo[]; homeData: any; // 建议替换为实际的首页数据类型 }; const initialState: TodosState = { list: [], error: null, status: "idle", homeData: null, }; export const selectStatus = (state: RootState) => state.todos.status; export const selectHomeData = (state: RootState) => state.todos.homeData; export const todosSlice = createSlice({ name: "todos", initialState, reducers: {}, extraReducers: (builder) => { // 原有fetchTodos处理逻辑... builder.addCase(fetchTodos.pending, (state) => { state.status = "loading"; state.error = null; }); builder.addCase(fetchTodos.fulfilled, (state, { payload }) => { state.list.push(...payload); state.status = "idle"; }); builder.addCase(fetchTodos.rejected, (state, { payload }) => { if (payload) state.error = payload.message; state.status = "idle"; }); // 新增getHomeData的状态处理 builder.addCase(getHomeData.pending, (state) => { state.status = "loading"; state.error = null; }); builder.addCase(getHomeData.fulfilled, (state, { payload }) => { state.homeData = payload; state.status = "idle"; }); builder.addCase(getHomeData.rejected, (state, action) => { state.error = action.error.message || "获取首页数据失败"; state.status = "idle"; }); }, }); export default todosSlice.reducer
3. 优化 getHomeData 的类型定义(可选但推荐)
避免使用 any,定义明确的返回类型:
// 定义首页数据类型 export type HomeData = { // 根据API返回结构定义字段 id: string; title: string; // ...其他字段 }; export const getHomeData = createAsyncThunk<HomeData, void>( 'actions/getHomeData', async () =>{ const response = await API.get(configAEM.apis.home); const data = await response.json(); return data; } );
内容的提问来源于stack exchange,提问作者user968597
相关产品推荐
相关产品推荐

