You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redux Toolkit过滤状态触发Immer返回新值并修改草稿报错如何解决

问题原因

Redux Toolkit 内部使用 Immer 处理不可变数据更新,要求 reducer 逻辑只能二选一:要么直接修改入参的 draft state 对象,要么返回一个全新的 state 值,不能同时执行两个操作。
你当前的searchTerm reducer 同时做了两件触发冲突的事:

  • 执行state.value = action.payload修改了 draft state
  • 最后执行return state.list返回了新值

同时你还存在两个逻辑错误:

  • Array.filter()不会修改原数组,直接调用state.list.filter()不会生效,必须把返回的新数组赋值给state
  • 直接修改原始的list会丢失全量国家数据,后续搜索只能基于上一次过滤的结果查询,无法回到全量数据

修复方案

1. 调整 search.js slice 代码

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';

export const getCountries = createAsyncThunk(
    'searchDefault/getCountries', async () => {
        try {
            const resp = await axios.get('https://restcountries.com/v2/all');
            return resp.data;
        } catch (error) {
            console.log(error.message);
        }
    }
)

const searchSlice = createSlice({
    name: 'searchDefault',
    initialState: {
        originalList: [], // 新增:存储全量原始国家数据,不做修改
        list: [], // 存储当前渲染的过滤后数据
        status: null,
        value: ''
    },
    reducers: {
        searchTerm: (state, action) => {
            const keyword = action.payload.trim().toLowerCase();
            state.value = action.payload;
            // 基于原始全量数据过滤,结果赋值给渲染用的list
            state.list = state.originalList.filter(country => 
                country.name.toLowerCase().includes(keyword)
            );
            // 不要写return,Immer会自动基于你修改的draft生成新state
        }
    },
    extraReducers: {
        [getCountries.pending]: (state) => {
            state.status = 'loading'
        },
        [getCountries.fulfilled]: (state, {payload}) => {
            state.originalList = payload; // 全量数据存到originalList
            state.list = payload; // 初始渲染用全量数据
            state.status = 'success'
        },
        [getCountries.rejected]: (state) => {
            state.status = 'failed'
        }
    }
})

export const { searchTerm } = searchSlice.actions;
export default searchSlice.reducer;

2. 修复 SearchBar.js 取值逻辑

你之前取query的时候拿了整个slice的state对象,需要精准取value字段:

import React from 'react';
import {useSelector, useDispatch} from 'react-redux';
import { searchTerm } from '../redux/search';

const SearchBar = () => {
    // 修正取值路径
    const query = useSelector((state) => state.searchDefault.value);
    const dispatch = useDispatch();

    return (
        <form onSubmit={(e) => e.preventDefault()}> {/* 阻止表单默认提交刷新页面 */}
            <input 
                className="search" 
                type="search" 
                placeholder="Search for a country" 
                value={query}
                onChange={(e) => dispatch(searchTerm(e.target.value))}/>
        </form>
    )
}

export default SearchBar;

3. 修正 Home.js 取值路径

如果你的store注册reducer时用的key和slice的name一致为searchDefault,需要调整取值路径:

// 其他代码保持不变
const countries = useSelector((state) => state.searchDefault);

内容的提问来源于stack exchange,提问作者Micah johnson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 01:09:03