如何将Hook中的状态存入Redux Toolkit Store?
问题分析与解决方案
核心错误原因
你在createAsyncThunk的异步函数里直接调用了useBalances这个React Hook,这违反了React Hook的使用规则:Hook只能在React函数组件的顶层、或者自定义Hook的顶层调用,绝对不能在普通异步函数、循环、条件判断里调用。这直接导致React抛出错误,触发了thunk的rejected状态,所以你的Redux store里error被设为true。
另外你的thunk逻辑还有两个小问题:
forEach里的return不会终止循环也不会返回值,应该用find来定位目标余额项- 没有处理异步等待逻辑,
useBalances内部是异步请求,但你同步拿data根本获取不到异步返回的结果
解决方案一:组件内使用Hook后同步到Redux
既然组件里调用useBalances是正常的,那可以在组件中拿到数据后,dispatch一个普通action把数据存入store:
1. 新增同步action
// 在accounts slice中新增同步action export const setAccountBalance = createAction<number>("accounts/setBalance");
2. 更新reducer处理同步action
export const accountsReducer = createReducer(initialState, (builder) => { builder .addCase(getAccounts.pending, (state) => { state.pending = true; }) .addCase(getAccounts.fulfilled, (state, { payload }) => { state.pending = false; state.amount = payload.amount; }) .addCase(getAccounts.rejected, (state) => { state.pending = false; state.error = true; }) // 新增同步action的处理逻辑 .addCase(setAccountBalance, (state, action) => { state.amount = action.payload; }); });
3. 在组件中使用Hook并同步数据
const dispatch = useAppDispatch(); const { amount, pending, error } = useAppSelector(accountsSelector); const account = "name"; const { data, isFetching } = useBalances(account); // 当data更新时,自动同步到Redux useEffect(() => { if (data) { const targetBalance = data.find(balance => balance.title === "name"); if (targetBalance) { dispatch(setAccountBalance(Number.parseInt(targetBalance.amount))); } } }, [data, dispatch]); return ( <div> {isFetching && <p>Fetching balances...</p>} {amount && <p>redux amount: {amount}</p>} {error && <p>Error occurred!</p>} </div> );
解决方案二:直接在thunk中调用原始API
如果一定要在Redux thunk里获取数据,你需要找到useBalances内部实际调用的API请求函数(比如fetchBalances(account)),而非直接使用Hook。假设useBalances内部的原始API函数是这样的:
// 示例:useBalances内部封装的API请求函数 export const fetchBalances = async (account: string) => { const res = await fetch(`/api/balances/${account}`); return res.json(); };
那你可以修改thunk直接调用这个API:
修正后的thunk代码
export const getAccounts = createAsyncThunk("accounts/getBalance", async () => { const account = "name"; try { // 直接调用原始API,避免使用Hook const data = await fetchBalances(account); const targetBalance = data.find(balance => balance.title === "name"); if (targetBalance) { return { amount: Number.parseInt(targetBalance.amount) }; } } catch (e) { // 抛出错误,让thunk进入rejected状态 throw e; } return { amount: 0 }; });
这样就能避免在thunk中调用Hook的违规操作,同时正确处理异步请求。
额外注意点
- 非组件/非自定义Hook的场景绝对不能调用React Hook,这是硬性规则
- 查找单个元素时,
find比forEach更合适,forEach无法通过return返回结果 - 异步操作必须加
await,否则无法获取异步返回的数据
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

