Как я могу генерировать событие сокета в useEffect на основе параметров маршрута? - PullRequest
1 голос
/ 26 марта 2020

Я использую React и Socket.io, чтобы создать какой-то клон Slack. В моем случае я пытаюсь объединить namespaces и rooms.

Я присоединяюсь к namespace, передавая параметры маршрута в моем маршруте React Router.

У меня есть следующие маршруты:

<Switch>
  <Route path={'/server/:id'} component={ServerContentPage} />
</Switch>

и внутри ServerContentPage У меня есть:

<Route exact path={'/server/:id/room/:roomID'} component={ChatPage} />

, поэтому маршрут ChatPage вложен в ServerContentPage.

Объединение пространства имен (рендеринг ServerContentPage) работает правильно, затем я сопоставляю все комнаты, извлеченные из базы данных MongoDB, и создаю React Links, который перенаправляет меня на правильный маршрут и правильно отображает компонент.

{rooms.map(room => (
  <StyledLink to={`/server/${currentNamespaceID}/room/${room._id}`} key={room._id}>
    <StyledParagraph>{room.name}</StyledParagraph>
  </StyledLink>
))}

Когда я нажимаю Link, он отображает ChatPage, как и ожидалось, затем я хочу, чтобы эта страница отправила сокет на сервер с roomID, который будет моей комнатой, к которой я должен присоединиться.

  • ChatPage. js
import React, { useContext, useEffect } from 'react';
import { connect } from 'react-redux';
import NamespaceSocketContext from '../providers/namespaceSocketContext';


const ChatPage = ({ match, setCurrentRoom }) => {
  const { namespaceSocket } = useContext(NamespaceSocketContext);

  useEffect(() => {
    namespaceSocket.emit('join_room', match.params.roomID);
    console.log('should emit join');


    namespaceSocket.on('user_joined', roomID => {
      console.log(`user joined to the room room ${roomID}`);
      setCurrentRoom(roomID);
    });

    namespaceSocket.on('user_left', roomID => {
      console.log(`user left room ${roomID}`);
      setCurrentRoom(null);
    });

    return () => {
      console.log('should emit leave');
      namespaceSocket.emit('leave_room', match.params.roomID);
    };
  }, [match.params.roomID]);


  return (
    <p>...some content</p>
  );
};


const mapDispatchToProps = dispatch => {
  return {
    setCurrentRoom: roomID => dispatch(setCurrentRoom(roomID))
  };
};


export default connect(null, mapDispatchToProps)(ChatPage);

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

  • index. js (сервер)

namespaceController
    .getAllNamespaces()
    .then(namespaces =>
      namespaces.map(item => {
        io.of(`/${item._id}`)
          .use((namespaceSocket, next) => {
            socketAuthentication(namespaceSocket, next);
          })
          .on('connection', namespaceSocket => {
            const currentNamespace = io.of(`/${item._id}`);

            /* join room */
            namespaceSocket.on('join_room', roomID => {

              namespaceSocket.join(roomID);
              console.log(`user joined room ${roomID}`);

              /* emit event back, user joined to the room */
              namespaceSocket.emit('user_joined', roomID);
            });

            /* leave room */
            namespaceSocket.on('leave_room', roomID => {
              namespaceSocket.leave(roomID);

              namespaceSocket.emit('user_left', roomID);
              console.log(`User left room ${roomID}`);
            });
          });
      })
    )
    .catch(error => console.log(error));

Когда я открою этот ChatPage через React Router Link, я получу вывод на консоль браузера:

should emit join

, что может выглядеть правильно, но сервер не входит в комнату. На моей консоли сервера я никогда не получу user joined room {some.id}. Кроме того, когда я захочу изменить комнату, щелкнув другую ссылку, я получу вывод на консоль браузера:

should emit leave
should emit join
user left room {some.id}

Итак, снова похоже, что функция очистки работает правильно, из-за чего сервер покидает room, он отправляет событие user_left обратно клиенту, но не присоединяется к комнате, даже вместо этого журнала консоли.

  • Я попытался использовать немного другой подход и добавить к функции Link onClick, которая может выдавать событие join_room при нажатии на ссылку, затем удалить namespaceSocket.emit('join_room', match.params.roomID) из ChatPage useEffect .

Это работает, но это немного странно, потому что событие join_room отправляется на сервер при первом клике по ссылке, клиент присоединяется к комнате, но я нет ответа сервера на стороне клиента. Только после второго щелчка я получил user joined room {some.id} назад.

Возможно, это проблема useEffect match.params, но я не могу найти решение. Может быть, кто-нибудь сможет мне помочь.

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