如何用Apollo useQuery取数并通过Redux Toolkit设置initialState?
解决方案:在Redux Toolkit中整合GraphQL数据获取
你遇到的核心问题是React Hook(如useQuery)只能在函数组件或自定义Hook内部调用,无法直接在Redux slice这类非Hook/组件的代码块中使用。下面提供两种可行的实现方案,适配你的MERN+GraphQL技术栈:
方案一:用createAsyncThunk结合Apollo Client直接查询
通过Apollo Client的client.query方法(非Hook版本)在异步thunk中执行GraphQL查询,再将结果同步到Redux状态中。
步骤1:导出Apollo Client实例
确保你有一个全局的Apollo Client实例可以导入:
// apolloClient.js import { ApolloClient, InMemoryCache } from '@apollo/client'; const client = new ApolloClient({ uri: '/graphql', // 你的GraphQL端点地址 cache: new InMemoryCache(), }); export default client;
步骤2:修改settings slice,添加异步thunk
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"; import client from "../apolloClient"; import { GET_USER_SETTINGS } from "../graphql/queries/settingsQueries"; // 创建异步thunk,负责获取用户设置 export const fetchUserSettings = createAsyncThunk( 'settings/fetchUserSettings', async () => { const { data } = await client.query({ query: GET_USER_SETTINGS }); return data.settings; } ); const initialState = { gridView: false, // 设置默认值 loading: false, error: null, }; const settingsSlice = createSlice({ name: "settings", initialState, reducers: { setGridViewOff(state) { state.gridView = false; }, setGridViewOn(state) { state.gridView = true; }, }, // 处理异步thunk的状态更新 extraReducers: (builder) => { builder .addCase(fetchUserSettings.pending, (state) => { state.loading = true; state.error = null; }) .addCase(fetchUserSettings.fulfilled, (state, action) => { state.loading = false; state.gridView = action.payload.gridView; }) .addCase(fetchUserSettings.rejected, (state, action) => { state.loading = false; state.error = action.error.message; }); }, }); export const { setGridViewOff, setGridViewOn } = settingsSlice.actions; export default settingsSlice.reducer;
步骤3:在组件中触发异步查询
在应用初始化的组件(如App.js)中调用thunk,触发数据获取:
import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { fetchUserSettings } from './slices/settingsSlice'; function App() { const dispatch = useDispatch(); useEffect(() => { dispatch(fetchUserSettings()); }, [dispatch]); return <div>...</div>; } export default App;
方案二:组件内用useQuery,同步结果到Redux
如果组件本身需要使用useQuery的查询结果,可以在组件内完成查询后,通过dispatch将数据存入Redux。
步骤1:在slice中添加同步数据的reducer
import { createSlice } from "@reduxjs/toolkit"; const initialState = { gridView: false, }; const settingsSlice = createSlice({ name: "settings", initialState, reducers: { setGridViewOff(state) { state.gridView = false; }, setGridViewOn(state) { state.gridView = true; }, // 添加同步用户设置的reducer setUserSettings(state, action) { state.gridView = action.payload.gridView; // 若有其他设置字段,可扩展为:state = { ...state, ...action.payload } }, }, }); export const { setGridViewOff, setGridViewOn, setUserSettings } = settingsSlice.actions; export default settingsSlice.reducer;
步骤2:在组件中执行查询并同步到Redux
import { useQuery } from "@apollo/client"; import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { setUserSettings } from './slices/settingsSlice'; import { GET_USER_SETTINGS } from "../graphql/queries/settingsQueries"; function SettingsComponent() { const { loading, error, data } = useQuery(GET_USER_SETTINGS); const dispatch = useDispatch(); // 查询完成后同步到Redux useEffect(() => { if (data?.settings) { dispatch(setUserSettings(data.settings)); } }, [data, dispatch]); if (loading) return <p>加载中...</p>; if (error) return <p>错误:{error.message}</p>; return <div>...</div>; }
方案选择建议
- 若希望Redux完全管理数据获取的异步状态(loading/error),优先选择方案一;
- 若组件本身需要直接使用
useQuery的结果,同时需要同步到Redux,选择方案二更简洁。
内容的提问来源于stack exchange,提问作者jonteal
相关产品推荐
相关产品推荐

