React Apollo useSubscription钩子直接调用无响应,赋值变量则正常
Apollo GraphQL订阅客户端无法触发onData回调的问题
服务器端订阅功能正常,但客户端调用useSubscription时,直接调用无日志输出:
useSubscription(BOOK_ADDED, { onData: ({ data }) => { console.log(data) } })
但将调用结果赋值给变量后,onData能正常打印数据:
const value = useSubscription(BOOK_ADDED, { onData: ({ data }) => { console.log(data) } }) console.log(value)
相关配置及代码
index.js(Apollo配置)
import ReactDOM from 'react-dom' import App from './App' import { ApolloClient, ApolloProvider, HttpLink, InMemoryCache, split, } from '@apollo/client' import { setContext } from '@apollo/client/link/context' import { getMainDefinition } from '@apollo/client/utilities' import { GraphQLWsLink } from '@apollo/client/link/subscriptions' import { createClient } from 'graphql-ws' import Assess from './Asses' const authLink = setContext((_, { headers }) => { const token = localStorage.getItem('library-user-token') return { headers: { ...headers, authorization: token ? `bearer ${token}` : null, }, } }) const httpLink = new HttpLink({ uri: 'http://localhost:4002' }) const wsLink = new GraphQLWsLink( createClient({ url: 'ws://localhost:4002', }) ) const splitLink = split( ({ query }) => { const definition = getMainDefinition(query) return ( definition.kind === 'OperationDefinition' && definition.operation === 'subscription' ) }, wsLink, authLink.concat(httpLink) ) const client = new ApolloClient({ cache: new InMemoryCache(), link: splitLink, }) ReactDOM.render( <ApolloProvider client={client}> <Assess /> </ApolloProvider>, document.getElementById('root') )
App.js
//App.js import { useSubscription, useQuery } from "@apollo/client"; import { ALL_BOOKS, BOOK_ADDED } from "./queries"; const App = () => { console.log(BOOK_ADDED); const result = useQuery(ALL_BOOKS); useSubscription(BOOK_ADDED, { onData: ({ data }) => { console.log(data); }, }); console.log(result) if(result.loading){ return null } return ( <div> {result?.data?.allBooks.map((r) => ( <li key={r.id}>{r.title}</li> ))} </div> ); }; export default App
查询及片段
const BOOK_DETAILS = gql` fragment BookDetails on Books { title author { name } published genres id } `; export const BOOK_ADDED = gql` subscription { bookAdded { ...BookDetails } } ${BOOK_DETAILS} `;
问题原因及解决方案
核心原因
这个现象是React Hooks的执行机制导致的:当你不接收useSubscription的返回值时,React或Apollo Client的内部优化逻辑可能会跳过订阅的完整初始化流程,导致onData回调没有被正确注册。
快速解决
只需接收useSubscription的返回值即可,哪怕不需要用到该值:
// 接收返回值,无需额外操作 const _ = useSubscription(BOOK_ADDED, { onData: ({ data }) => { console.log(data); }, });
额外检查点
- 组件挂载验证:确认
<App />确实被<Assess />组件渲染,若App未挂载,订阅不会生效。 - WebSocket连接状态:在浏览器开发者工具的Network标签下,检查WS连接是否成功建立,是否收到服务器推送的数据。
- WebSocket权限配置:你的
authLink仅处理了HTTP请求的权限头,WebSocket连接需要单独配置认证信息,否则服务器可能拒绝订阅请求:
const wsLink = new GraphQLWsLink( createClient({ url: 'ws://localhost:4002', connectionParams: () => { const token = localStorage.getItem('library-user-token'); return { authorization: token ? `bearer ${token}` : null, }; }, }) );
内容的提问来源于stack exchange,提问作者thefarerevenant
相关产品推荐
相关产品推荐

