React Redux如何将API数据展示在Select并实现州城联动?
问题分析与解决方案
核心问题定位
- Redux数据存储错误:你的API返回的是包含
data数组的响应对象,但当前slice可能把整个响应对象存在了dataState里,导致组件中states不是数组,无法执行map渲染选项。 - 本地状态调用错误:
handleChange里错误地用dispatch调用组件本地的setStateSelected,这是React useState的setter,不需要Redux dispatch。 - 缺少城市数据联动逻辑:未实现选中州后触发城市数据请求的逻辑。
步骤1:修正States Slice的数据存储
首先确保你的statesSlice.js正确提取API响应中的数组并存储:
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; import axios from 'axios'; // 定义获取州数据的异步action export const getStates = createAsyncThunk( 'states/getStates', async () => { const response = await axios.get('你的本地API地址'); // 提取响应中的data数组(根据你的API返回结构调整) return response.data.data; } ); const initialState = { data: [], // 存储州的数组 status: 'idle', // 标记请求状态:idle/loading/succeeded/failed error: null }; const statesSlice = createSlice({ name: 'states', initialState, reducers: {}, extraReducers: (builder) => { builder .addCase(getStates.pending, (state) => { state.status = 'loading'; }) .addCase(getStates.fulfilled, (state, action) => { state.status = 'succeeded'; state.data = action.payload; // 将数组存入state.data }) .addCase(getStates.rejected, (state, action) => { state.status = 'failed'; state.error = action.error.message; }); } }); export default statesSlice.reducer;
步骤2:修复SelectState组件
调整组件中数据获取和状态更新逻辑:
import React, { useState, useEffect } from "react"; import { FormControl, InputLabel, MenuItem, Select } from "@mui/material"; import { useDispatch, useSelector } from "react-redux"; import { getStates } from "../states/statesSlice"; import { getCitiesByState } from "../cities/citiesSlice"; // 后续会创建的城市slice export const SelectState = () => { const dispatch = useDispatch(); // 正确获取Redux中的州数组 const states = useSelector((state) => state.states.data); const statesStatus = useSelector((state) => state.states.status); const [stateSelected, setStateSelected] = useState(""); // 初始化请求州数据 useEffect(() => { if (statesStatus === 'idle') { dispatch(getStates()); } }, [dispatch, statesStatus]); // 选中州后,触发对应城市的请求 useEffect(() => { if (stateSelected) { dispatch(getCitiesByState(stateSelected)); } }, [dispatch, stateSelected]); // 直接调用本地setter更新选中状态,无需dispatch const handleChange = (event) => { setStateSelected(event.target.value); }; return ( <FormControl sx={{ m: 1, minWidth: 120 }} size="small"> <InputLabel id="demo-select-small">State</InputLabel> <Select labelId="demo-select-small" id="demo-select-small" value={stateSelected} label="estados" onChange={handleChange} > <MenuItem disabled>Select a state</MenuItem> {/* 现在states是数组,可以正常map渲染 */} {states.map((item) => ( <MenuItem key={item.id} value={item.sigla}> {item.nome} </MenuItem> ))} </Select> </FormControl> ); };
步骤3:创建Cities Slice实现联动
新建citiesSlice.js,用于处理城市数据请求:
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; import axios from 'axios'; // 根据州缩写获取城市数据 export const getCitiesByState = createAsyncThunk( 'cities/getCitiesByState', async (stateSigla) => { const response = await axios.get(`你的本地城市API地址?state=${stateSigla}`); return response.data.data; // 同样根据API返回结构调整 } ); const initialState = { data: [], status: 'idle', error: null }; const citiesSlice = createSlice({ name: 'cities', initialState, reducers: {}, extraReducers: (builder) => { builder .addCase(getCitiesByState.pending, (state) => { state.status = 'loading'; }) .addCase(getCitiesByState.fulfilled, (state, action) => { state.status = 'succeeded'; state.data = action.payload; }) .addCase(getCitiesByState.rejected, (state, action) => { state.status = 'failed'; state.error = action.error.message; }); } }); export default citiesSlice.reducer;
步骤4:创建SelectCity组件
新建城市选择组件,渲染Redux中的城市数据:
import React, { useState } from "react"; import { FormControl, InputLabel, MenuItem, Select } from "@mui/material"; import { useSelector } from "react-redux"; export const SelectCity = () => { const cities = useSelector((state) => state.cities.data); const [citySelected, setCitySelected] = useState(""); const handleChange = (event) => { setCitySelected(event.target.value); }; return ( <FormControl sx={{ m: 1, minWidth: 120 }} size="small"> <InputLabel id="demo-select-city">City</InputLabel> <Select labelId="demo-select-city" id="demo-select-city" value={citySelected} label="cities" onChange={handleChange} disabled={cities.length === 0} > <MenuItem disabled>Select a city</MenuItem> {cities.map((city) => ( <MenuItem key={city.id} value={city.nome}> {city.nome} </MenuItem> ))} </Select> </FormControl> ); };
步骤5:更新Store配置
在store.js中添加城市reducer:
import { configureStore } from '@reduxjs/toolkit'; import statesReducer from './states/statesSlice'; import citiesReducer from './cities/citiesSlice'; export const store = configureStore({ reducer: { states: statesReducer, cities: citiesReducer } });
内容的提问来源于stack exchange,提问作者Begginer
相关产品推荐
相关产品推荐

