Странная ошибка при использовании React useQuery (GraphQL) и useEffect + websockets - PullRequest
0 голосов
/ 11 июля 2020

Итак, у меня эта странная ошибка, и мне понадобится помощь, чтобы определить, откуда она вообще.

Чтобы лучше проиллюстрировать ошибку, я сделал скринкаст, который вы можете найти здесь: https://www.youtube.com/watch?v=MuXOfbYB_CI

Описание. На видео вы можете увидеть, как я использую свое приложение для подсчета очков, где левое окно - это контроллер для ввода бросков, а правое окно - это табло. После запуска игровые сайты будут перенаправлены на контроллер и табло через веб-сокеты. Итак, в следующий раз я заканчиваю игру, нажимая соответствующую кнопку, и сразу же начинаю новую игру таким же образом. При последующем вводе первого броска через контроллер возникнет ошибка.

Оба сайта (контроллер и табло выдают эту ошибку):

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. Поэтому каждый раз, когда я ввожу бросок (вызов API throw / number / modifier), api будет возвращать socket.emit('updateScoreboard') после обработки throw, а затем табло и контроллер извлекают последние данные, чтобы отразить изменения.

Но как вы можно увидеть по ошибке, покинув сторону один раз и вернувшись к ней, метода refetch как-то не будет. Как я могу предотвратить эту ошибку.

Когда я затем после короткого ожидания нажимаю Enter в обеих адресных строках браузера windows, и сайты перезагружаются, все снова будет в порядке и будет работать как задумано. Поскольку эта система должна работать в режиме киоска позже, обновление страницы, тем не менее, не является хорошим решением.

Любые инструкции будут высоко оценены

Решение

@ 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 за правильную подсказку и ресурс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...