使用Redux Toolkit检测到状态中非序列化值的问题排查
问题分析与解决方案
错误核心原因
你遇到的非序列化值错误和res.json无关,后端返回数据的方式是正确的。问题出在两个关键地方:
- Redux状态存了React元素:Redux要求状态必须是可序列化的纯数据(对象、数组、字符串、数字等),但你在
morphemeCheck2里直接返回<span>这类React元素,还把结果存在preppedWord状态里,这直接触发了非序列化值检测错误。 - 异步逻辑误用:
prefixCheck是异步函数(依赖api.getPrefixes().then()),但你在同步的reducer和JSX渲染里直接调用它,会返回Promise而非预期的内容,同时reducer本身不允许执行异步操作。
分步解决方案
1. 重构Redux状态:只存纯数据
把preppedWord改成存储词素分析后的纯数据结构,而非JSX元素:
const wordSlice = createSlice({ name: 'word', initialState: { word: '', preppedWord: [] // 改为存储词素数据数组,比如[{prefix: "", base: "", suffix: ""}, ...] }, reducers: { setWord(state, action) { state.word = action.payload }, setPreppedWord(state, action) { state.preppedWord = action.payload // 只存纯数据 }, // ...其他reducer逻辑 })
2. 把异步词素处理移到Redux异步Action中
Redux reducer必须是纯同步函数,异步逻辑要放到Thunk(Redux Toolkit默认集成)里:
// 异步Action:先获取前缀/后缀数据,再处理词素拆分 export const fetchAndCheckMorphemes = (word) => async (dispatch) => { try { // 异步获取数据库中的前缀、后缀数据 const prefixes = await api.getPrefixes(); const suffixes = await api.getSuffixes(); // 假设你有对应的后缀接口 // 拆分词素,生成纯数据数组 const preppedData = word.split(' ').map((wordItem) => { let prefix = ''; // 匹配前缀 for (let p of prefixes) { if (wordItem.startsWith(p.affix_name)) { prefix = p.affix_name; break; } } // 计算词根(去掉前缀后) let base = prefix ? wordItem.slice(prefix.length) : wordItem; let suffix = ''; // 匹配后缀 for (let s of suffixes) { if (base.endsWith(s.affix_name)) { suffix = s.affix_name; base = base.slice(0, base.length - suffix.length); break; } } return { prefix, base, suffix }; }); // 把处理后的纯数据存入Redux状态 dispatch(setPreppedWord(preppedData)); } catch (err) { console.error('词素处理失败:', err); } }
3. 在组件中根据Redux数据渲染JSX
组件从Redux拿到纯数据后,再在组件内部渲染对应的DOM元素:
import { useDispatch, useSelector } from 'react-redux'; import { setWord, fetchAndCheckMorphemes } from './wordSlice'; function WordAnalyzer() { const dispatch = useDispatch(); const { word, preppedWord } = useSelector(state => state.word); const handleInputChange = (e) => { const newWord = e.target.value; dispatch(setWord(newWord)); // 触发异步词素分析 dispatch(fetchAndCheckMorphemes(newWord)); }; return ( <div> <input value={word} onChange={handleInputChange} placeholder="输入单词" /> <div className="word-breakdown"> {preppedWord.map((item, index) => ( <span key={index}> {item.prefix && <span className={`prefix ${item.prefix}`}>{item.prefix}</span>} <span className="base-word">{item.base}</span> {item.suffix && <span className={`suffix ${item.suffix}`}>{item.suffix}</span>} </span> ))} </div> </div> ); }
后端代码无需修改
你的后端router.get('/prefixes')用res.json(result)返回数据是完全正确的,这不是问题所在。
内容的提问来源于stack exchange,提问作者vygrdev
相关产品推荐
相关产品推荐

