使用React useQuery(GraphQL)和useEffect + websockets的奇怪错误

时间:2020-07-11 11:54:53

标签: reactjs sqlite rest socket.io graphql

所以我有这个奇怪的错误,需要帮助确定它的来源。

为了更好地说明该错误,我进行了截屏,您可以在此处找到https://www.youtube.com/watch?v=MuXOfbYB_CI

说明:您在视频中看到的是我使用我的dart记分器应用程序,其中左侧窗口是输入掷球的控制器,右侧窗口是记分板。开始游戏后,网站将通过websockets重定向到控制器和计分板。
因此,接下来我要通过单击相应的按钮来结束游戏,然后立即以相同的方式开始新游戏。 然后,当通过控制器输入第一个掷球时,将发生错误。

两个站点(控制器和记分板均抛出此错误):

QueryData.ts:445 Uncaught TypeError: Cannot read property 'refetch' of undefined
    at QueryData._this.obsRefetch (QueryData.ts:445)
    at Socket.<anonymous> (ControllerPage.jsx:24)
    at Socket.push../node_modules/socket.io-client/node_modules/component-emitter/index.js.Emitter.emit (index.js:133)
    at Socket.push../node_modules/socket.io-client/lib/socket.js.Socket.onevent (socket.js:278)
    at Socket.push../node_modules/socket.io-client/lib/socket.js.Socket.onpacket (socket.js:236)
    at Manager.<anonymous> (index.js:21)
    at Manager.push../node_modules/socket.io-client/node_modules/component-emitter/index.js.Emitter.emit (index.js:133)
    at Manager.push../node_modules/socket.io-client/lib/manager.js.Manager.ondecoded (manager.js:345)
    at Decoder.<anonymous> (index.js:21)
    at Decoder.push../node_modules/socket.io-parser/node_modules/component-emitter/index.js.Emitter.emit (index.js:133)
    at Decoder.push../node_modules/socket.io-parser/index.js.Decoder.add (index.js:251)
    at Manager.push../node_modules/socket.io-client/lib/manager.js.Manager.ondata (manager.js:335)
    at Socket.<anonymous> (index.js:21)
    at Socket.push../node_modules/component-emitter/index.js.Emitter.emit (index.js:145)
    at Socket.push../node_modules/engine.io-client/lib/socket.js.Socket.onPacket (socket.js:461)
    at WS.<anonymous> (socket.js:278)
    at WS.push../node_modules/component-emitter/index.js.Emitter.emit (index.js:145)
    at WS.push../node_modules/engine.io-client/lib/transport.js.Transport.onPacket (transport.js:149)
    at WS.push../node_modules/engine.io-client/lib/transport.js.Transport.onData (transport.js:141)
    at WebSocket.ws.onmessage (websocket.js:160)
QueryData._this.obsRefetch @ QueryData.ts:445
(anonymous) @ ControllerPage.jsx:24
push../node_modules/socket.io-client/node_modules/component-emitter/index.js.Emitter.emit @ index.js:133
push../node_modules/socket.io-client/lib/socket.js.Socket.onevent @ socket.js:278
push../node_modules/socket.io-client/lib/socket.js.Socket.onpacket @ socket.js:236
(anonymous) @ index.js:21
push../node_modules/socket.io-client/node_modules/component-emitter/index.js.Emitter.emit @ index.js:133
push../node_modules/socket.io-client/lib/manager.js.Manager.ondecoded @ manager.js:345
(anonymous) @ index.js:21
push../node_modules/socket.io-parser/node_modules/component-emitter/index.js.Emitter.emit @ index.js:133
push../node_modules/socket.io-parser/index.js.Decoder.add @ index.js:251
push../node_modules/socket.io-client/lib/manager.js.Manager.ondata @ manager.js:335
(anonymous) @ index.js:21
push../node_modules/component-emitter/index.js.Emitter.emit @ index.js:145
push../node_modules/engine.io-client/lib/socket.js.Socket.onPacket @ socket.js:461
(anonymous) @ socket.js:278
push../node_modules/component-emitter/index.js.Emitter.emit @ index.js:145
push../node_modules/engine.io-client/lib/transport.js.Transport.onPacket @ transport.js:149
push../node_modules/engine.io-client/lib/transport.js.Transport.onData @ transport.js:141
ws.onmessage @ websocket.js:160

有问题的代码部分如下:

const ControllerPage = () => {
  const { loading, error, data, refetch } = useQuery(queries.GET_ALL_GAMES);

  const [redirect, setRedirect] = useState(false);

  useEffect(() => {
    socket.on('redirect', (data) => {
      if (data['target'] === 'controller') {
        setRedirect(true);
      }
    });

    socket.on('updateScoreboard', () => {
      refetch();
    });
  }, [refetch]);

  if (loading) return <div>Loading</div>;
  if (error) throw error;

.... jada jada ...
render (
)
and so on

如您所见,我正在使用refetch方法在useQuery的定义中再次手动触发查询。因此,每次我输入throw(API调用throw / number / modifier)时,api都会在处理完throw之后返回socket.emit('updateScoreboard'),然后记分板和控制器将获取最新数据以反映更改。

但是从错误中可以看到,离开一侧一次并返回该错误之后,refetch方法将不存在。如何防止此错误。

当我等待一小段时间后,在浏览器窗口的两个地址栏中输入内容,然后重新加载网站,它将再次正常运行并可以正常工作。但是,由于此系统应该在以后的信息亭模式下运行,因此刷新页面并不是一个好的解决方案。

任何指导将不胜感激


解决方案

@ luke-dunscombe完全正确。

updateScoreboard必须清理。选择return () => socket.disconnect作为清理方法将不起作用,因为套接字将停止正常工作,但是对此进行了更改:

const ControllerPage = () => {
  const { loading, error, data, refetch } = useQuery(queries.GET_ALL_GAMES);

  const [redirect, setRedirect] = useState(false);

  useEffect(() => {
    socket.on('redirect', (data) => {
      if (data['target'] === 'controller') {
        setRedirect(true);
      }
    });

    socket.on('updateScoreboard', () => {
      refetch();
    });
    
    return () => socket.off('updateScoreboard');

  }, [refetch]);

  if (loading) return <div>Loading</div>;
  if (error) throw error;

从useEffect挂钩返回时,我通过停止收听效果很好的 updateScoreboard 事件来进行清理。

再次感谢@ luke-dunscombe寻求正确的提示和资源。

0 个答案:

没有答案