如何在React组件中调用graphql-ws createClient的on事件?
在React组件中处理graphql-ws的连接事件(opened/closed)
要在React组件内调用graphql-ws连接事件(opened/closed)对应的业务逻辑,核心是解决客户端回调与组件上下文隔离的问题。以下是两种可行的实现方案:
方案一:自定义Hook封装客户端,动态传入组件回调
把graphql-ws客户端的初始化逻辑封装到自定义Hook中,允许组件传入事件回调,并确保回调始终能访问最新的组件上下文。
自定义Hook实现
import { useState, useEffect, useRef } from 'react'; import { createClient } from 'graphql-ws'; import { GraphQLWsLink } from '@apollo/client/link/subscriptions'; export const useGraphqlWsClient = (onOpened, onClosed) => { const clientRef = useRef(null); const wsLinkRef = useRef(null); // 初始化客户端(仅执行一次) useEffect(() => { if (!clientRef.current) { const client = createClient({ url: GRAPHQL_WS_ENDPOINT ?? "", on: { opened: () => onOpened?.(), closed: () => onClosed?.(), }, }); clientRef.current = client; wsLinkRef.current = new GraphQLWsLink(client); } // 组件卸载时关闭客户端连接 return () => clientRef.current?.dispose(); }, []); // 更新回调函数(适配组件内回调的更新) useEffect(() => { if (!clientRef.current) return; clientRef.current.on.opened = () => onOpened?.(); clientRef.current.on.closed = () => onClosed?.(); }, [onOpened, onClosed]); return wsLinkRef.current; };
组件中使用
import { useGraphqlWsClient } from './useGraphqlWsClient'; const MyComponent = () => { const handleConnectionOpened = () => { // 组件内的业务逻辑,比如调用API fetch('/api/connection-status', { method: 'POST', body: JSON.stringify({ status: 'connected' }), }); }; const handleConnectionClosed = () => { // 组件内的业务逻辑 fetch('/api/connection-status', { method: 'POST', body: JSON.stringify({ status: 'disconnected' }), }); }; // 获取wsLink用于Apollo Client配置 const wsLink = useGraphqlWsClient(handleConnectionOpened, handleConnectionClosed); return <div>组件内容</div>; };
方案二:React Context共享客户端,组件内订阅事件
如果需要在多个组件中复用graphql-ws客户端,可以将客户端放到Context中,组件通过Context获取客户端后,自行绑定/解绑事件。
第一步:创建Context与Provider
import { createContext, useContext, useState, useEffect } from 'react'; import { createClient } from 'graphql-ws'; import { GraphQLWsLink } from '@apollo/client/link/subscriptions'; const GraphqlWsContext = createContext(null); export const GraphqlWsProvider = ({ children }) => { const [client, setClient] = useState(null); const [wsLink, setWsLink] = useState(null); useEffect(() => { const newClient = createClient({ url: GRAPHQL_WS_ENDPOINT ?? "", on: {}, // 留空,由组件自行绑定事件 }); const newWsLink = new GraphQLWsLink(newClient); setClient(newClient); setWsLink(newWsLink); return () => newClient.dispose(); }, []); return ( <GraphqlWsContext.Provider value={{ client, wsLink }}> {children} </GraphqlWsContext.Provider> ); }; export const useGraphqlWs = () => useContext(GraphqlWsContext);
第二步:组件中订阅事件
import { useEffect } from 'react'; import { useGraphqlWs } from './GraphqlWsProvider'; const MyComponent = () => { const { client } = useGraphqlWs(); useEffect(() => { if (!client) return; // 定义事件处理函数 const handleOpened = () => { console.log('WS连接成功'); // 组件内业务逻辑 }; const handleClosed = () => { console.log('WS连接断开'); // 组件内业务逻辑 }; // 绑定事件 client.on.opened = handleOpened; client.on.closed = handleClosed; // 组件卸载时解绑事件 return () => { client.on.opened = () => {}; client.on.closed = () => {}; }; }, [client]); return <div>组件内容</div>; };
注意事项
- 必须在组件卸载时清理事件绑定或关闭客户端,避免内存泄漏
- 如果回调依赖组件内的状态/Props,要确保回调始终是最新的(方案一中通过
useEffect监听回调变化实现) - 不要在组件外部直接绑定组件内的回调,否则组件卸载后回调仍可能被触发,导致错误
内容的提问来源于stack exchange,提问作者Biswas Rai
相关产品推荐
相关产品推荐

