先说说技术选型。前端用的是React 16.8+,主要是奔着Hooks去的,状态管理没上Redux,直接用的Apollo Client内置的cache。后端图省事,拿Nest.js搭了个GraphQL服务,用Apollo Server跑的。数据库是MongoDB,用Mongoose做的ODM。这里要提一嘴,Apollo Client 3.0以上的版本跟React的集成做得是真不错,缓存策略比早期版本智能多了。
具体实现分三步走。首先是搭建GraphQL服务端,定义Schema这块花了不少时间。看板需要聚合用户数据、订单统计和系统状态,我就写了三个Query类型:
Nest.js里用@Query()装饰器实现resolver的时候,要注意数据加载器(DataLoader)的使用,不然会遇到经典的N+1查询问题。我这边是把Mongoose的aggregate管道和DataLoader结合着用,性能提升挺明显。
前端集成才是重头戏。安装apollo-client和@apollo/react-hooks包之后,在index.js里初始化客户端:
然后用ApolloProvider包住根组件。在看板组件里,直接用useQuery钩子获取数据:
这里有个优化点:通过Apollo Client的fetchPolicy设置成cache-and-network,既能享受缓存带来的速度,又能保持数据更新。我还给看板加了每30秒自动刷新的功能,用useQuery返回的refetch方法就能实现。
踩坑记录必须得说说类型安全。最初没定义好输入参数类型,前端传了个整数给period参数,服务端直接报类型错误。后来用GraphQL Code Generator自动生成TypeScript类型定义,这才省心。还有缓存更新问题,刚开始 mutation 之后页面数据不更新,查文档才知道得手动更新cache,用writeQuery方法写入新数据。
性能监控方面,给Apollo Server加了插件记录查询耗时,发现有个订单统计查询特别慢。优化方法是在resolver里加了dataloader批量查询,响应时间从800ms降到了120ms左右。前端也做了查询去重,同一个查询在100ms内只发一次请求。
这次实践下来,GraphQL在复杂数据聚合场景确实优势明显。原先需要调三四个REST接口的工作,现在一个GraphQL查询就搞定了。不过也不是银弹,接口复杂度转移到了服务端,schema设计需要前后端密切配合。如果团队规模小、追求开发效率,这个技术栈值得一试。
另外补充个小技巧:用Chrome的Apollo Client Devtools插件调试特别方便,能实时查看缓存状态和查询轨迹。开发阶段建议一定要装上,能省不少排查时间。
下次准备试试GraphQL的订阅功能做实时通知,有成果再跟大家分享。各位要是在实践过程中遇到其他问题,欢迎在评论区交流。