为何不直接将GraphQL与Redux搭配使用?新项目选型困惑
GraphQL + Redux:完全可行的组合,只是你没注意到!
嘿,这个问题戳中了很多开发者的痛点——我懂你偏爱Redux单一Store那种“一切尽在掌控”的感觉,也理解为啥Apollo/Relay的独立Store会让你觉得别扭。其实GraphQL和Redux的搭配完全可行,只是因为Apollo/Relay把GraphQL的核心痛点(缓存、请求管理、数据同步)都打包解决了,所以大部分人直接用它们的方案,但如果你坚持Redux的设计思路,完全可以自己整合!
为啥大家默认用Apollo/Relay的Store?
- 它们帮你省了超多重复工作:GraphQL的缓存归一化、自动去重重复请求、数据更新时的自动同步,还有和React无缝绑定的Hooks(比如
useQuery、useMutation),这些逻辑要是自己写,得花不少时间。 - 很多人觉得“重复维护状态”没必要:Apollo本身已经做了状态管理的工作,再把数据转存到Redux里,等于多了一层冗余,反而增加维护成本。
怎么把GraphQL和Redux搭起来?
其实思路和你处理REST API几乎一样:用GraphQL客户端发起请求,拿到数据后dispatch到Redux Store就行。这里给你举个简单的例子:
步骤1:用轻量GraphQL客户端发起请求
比如用graphql-request(比Apollo轻很多):
import { request } from 'graphql-request'; import { dispatch } from './redux/store'; import { setUsers, setUsersLoading, setUsersError } from './redux/userSlice'; export const fetchUsers = async () => { try { dispatch(setUsersLoading(true)); const query = ` query GetUsers { users { id name email } } `; const data = await request('/your-graphql-endpoint', query); dispatch(setUsers(data.users)); } catch (error) { dispatch(setUsersError(error.message)); } finally { dispatch(setUsersLoading(false)); } };
步骤2:在Redux里管理状态
你的Slice可以和处理REST数据时一样,包含data、loading、error这些状态:
// redux/userSlice.js import { createSlice } from '@reduxjs/toolkit'; const initialState = { data: [], loading: false, error: null, }; const userSlice = createSlice({ name: 'users', initialState, reducers: { setUsers: (state, action) => { state.data = action.payload; }, setUsersLoading: (state, action) => { state.loading = action.payload; }, setUsersError: (state, action) => { state.error = action.payload; }, }, }); export const { setUsers, setUsersLoading, setUsersError } = userSlice.actions; export default userSlice.reducer;
步骤3:在React组件里使用
和你平时用Redux的方式一样,用useSelector获取数据,用useDispatch触发请求:
import { useSelector, useDispatch } from 'react-redux'; import { fetchUsers } from './fetchUsers'; function UserList() { const { data: users, loading, error } = useSelector(state => state.users); const dispatch = useDispatch(); useEffect(() => { dispatch(fetchUsers()); }, [dispatch]); if (loading) return <div>Loading...</div>; if (error) return <div>Error: {error}</div>; return ( <ul> {users.map(user => ( <li key={user.id}>{user.name} ({user.email})</li> ))} </ul> ); }
这么做的优势是什么?
- 保持单一Store的统一感:所有应用状态(不管是GraphQL数据、UI状态还是业务逻辑状态)都在同一个Store里,不用在Apollo Store和Redux Store之间来回切换。
- 完全掌控数据流程:你可以自定义数据的处理、缓存、更新逻辑,不受Apollo/Relay的约束,适合对状态管理有特殊需求的场景。
可能遇到的挑战?
- 需要自己处理GraphQL的高级特性:比如缓存归一化、乐观更新、订阅(GraphQL Subscription)这些,Apollo已经帮你封装好了,自己写的话会增加开发工作量。
- 没有Apollo Hooks的便捷性:你得自己封装Redux Hooks来处理数据的获取和状态,不像
useQuery那样一键搞定请求、加载、错误状态。
总结
GraphQL和Redux的搭配不是没人用,只是Apollo/Relay太“省心”了,所以成了主流。但如果你偏爱Redux的单一Store设计,完全可以按照自己的方式整合——核心就是把GraphQL当成一种新的数据源,像处理REST API一样把数据塞进Redux Store就行。
内容的提问来源于stack exchange,提问作者macieks
相关产品推荐
相关产品推荐

