Redux Toolkit中使用axios获取API数据报错如何解决
问题根因
你的代码存在3个直接触发报错的问题:
- 异步逻辑写法完全错误:
axios.get()返回的是Promise异步对象,你直接把这个对象存到了初始state里,根本没有拿到接口返回的实际数组数据 - Redux的reducer和state初始化逻辑必须是同步纯函数,Redux Toolkit(以下简称RTK)中所有异步请求需要用官方内置的
createAsyncThunk处理,不能直接在slice外层裸写请求塞值 - useSelector取值路径错误:你定义的slice初始state是
{value: xxx}结构,本身是个对象不是数组,直接对对象调用.map()方法必然触发「xxx.map is not a function」的类型错误,和你运行时的报错完全吻合 - 额外拼写问题:你的slice文件名、action名里的
compnay是拼写错误,正确拼写是company,虽然不直接触发报错,但很容易后续引发导入路径类的bug
修正后代码
1. 重写slice文件(修正文件名:companyList.js)
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; import axios from 'axios'; // 定义异步请求方法 export const fetchCompanies = createAsyncThunk( 'companyList/fetchCompanies', async () => { const res = await axios.get('https://mocki.io/v1/d4867d8b-b5d5-4a48-a4ab-79131b5809b8'); return res.data; } ); const companySlice = createSlice({ name: 'companyList', initialState: { value: [], loading: false, error: null }, reducers: { // 修正之前的拼写错误 addCompany: (state, action) => { state.value.push(action.payload); } }, // 监听异步请求的三个状态,更新state extraReducers: (builder) => { builder .addCase(fetchCompanies.pending, (state) => { state.loading = true; state.error = null; }) .addCase(fetchCompanies.fulfilled, (state, action) => { state.loading = false; state.value = action.payload; }) .addCase(fetchCompanies.rejected, (state, action) => { state.loading = false; state.error = action.error.message; }); } }); export const { addCompany } = companySlice.actions; export default companySlice.reducer;
2. 修正App.js
import { useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { fetchCompanies } from './features/companySlice/companyList'; function App() { const dispatch = useDispatch(); // 正确取到state里的数组、加载状态、错误信息 const { value: companies, loading, error } = useSelector(state => state.companyList); // 组件挂载时触发请求 useEffect(() => { dispatch(fetchCompanies()); }, [dispatch]); // 处理加载和报错场景 if (loading) return <div className="App">数据加载中...</div>; if (error) return <div className="App">请求失败:{error}</div>; return ( <div className="App"> <header className="App-header"> {companies.map(company => ( // 循环项必须加唯一key <h1 key={company.name}>{company.name}</h1> ))} <h1>hello</h1> </header> </div> ); } export default App;
3. 修正store.js的导入路径
import { configureStore } from '@reduxjs/toolkit'; // 修正之前的文件名拼写错误 import companyReducer from './features/companySlice/companyList'; export const store = configureStore({ reducer: { companyList: companyReducer } });
核心注意事项
- Redux的state必须是可序列化的普通数据,绝对不能把Promise、函数这类特殊对象直接存到state里
- RTK中不要在reducer、slice初始化逻辑里写异步代码,异步请求统一用
createAsyncThunk,如果是接口类场景多也可以直接用RTK Query,不用手写thunk - 写useSelector的时候一定要对应你自己定义的state结构,不要拿错数据层级
- 数组循环渲染必须给每一项加唯一的key属性,避免React渲染警告和异常
内容的提问来源于stack exchange,提问作者Ali Mozaffari
相关产品推荐
相关产品推荐

