如何使用MERN堆栈应用程序(以编程方式)将数据发送到websocket,而不是在React中使用受控形式?

时间:2020-06-03 17:35:18

标签: javascript node.js reactjs socket.io mern

编辑:我想使这个问题尽可能简洁,以免引起人们阅读时间的浪费。本质上,问题似乎出在我的Chat.js中。似乎启动套接字连接的useEffect搞砸了useEffect,试图从后端读取用户名。我相信我的问题取决于无法调用read()方法。因此,如果有人知道我的问题是使用useEffect获取数据的策略,那么我认为这将回答我的问题。

  useEffect(() => {
    const abortController = new AbortController()
    const signal = abortController.signal
    console.log(match.params.userId )
    read({
      userId: match.params.userId
    }, {t: jwt.token}, signal).then((data) => { 
        setValues({...values, user: data, following: following})
    })
    return function cleanup(){
      abortController.abort()
    }

  }, [match.params.userId])
  console.log(values)

  useEffect(() => {
    socket = io(ENDPOINT);
    setRoom(room);
    setName(name);

    socket.emit('join', { name, room }, (error) => {
      if(error) {
        alert(error);
      }
    });
  }, [ENDPOINT, location.search]);

原始问题: 我一直在尝试找到一种以编程方式将数据发送到后端Websocket服务器的方法。我希望用户能够单击我的聊天窗口并立即使用其现有帐户凭据登录。

现在,我有一个Join.js页面“ / chatroom”,用户可以在其中输入其姓名和房间。

import React, { useState, useEffect } from 'react';
import { Link } from "react-router-dom";
import {read} from '../../user/api-user.js'
import auth from '../../auth/auth-helper'
import './Join.css';

export default function SignIn(props) {

  const [name, setName] = useState('');
  const [room, setRoom] = useState('');
  const [values, setValues] = useState({
    user: '',
    redirectToSignin: false,
  })
  const jwt = auth.isAuthenticated()

  useEffect(() => {
    const abortController = new AbortController()
    const signal = abortController.signal

    read({
      userId: props.match.params.userId
    }, {t: jwt.token}, signal).then((data) => {
      if (data && data.error) {
        setValues({...values,redirectToSignin: true})
      } else {
        var c  = {...values, user:data}
        setValues(c)

      }
    })

    return function cleanup(){
      abortController.abort()
    }
  }), []

  console.log(values.user.name)
  const myname = values.user.name


  return (
    <div className="joinOuterContainer">
      <div className="joinInnerContainer">
        <h1 className="heading">Join</h1>
        <div>
          <input placeholder="Name" className="joinInput" type="text" onChange={(event) => setName(event.target.value)} />
        </div>
        <div>
          <input placeholder="Room" className="joinInput mt-20" type="text" onChange={(event) => setRoom(event.target.value)} />
        </div>
        <Link onClick={e => (!name || !room) ? e.preventDefault() : null} to={`/chat?name=${name}&room=${room}`}>
          <button className={'button mt-20'} type="submit">Sign In</button>
        </Link>
      </div>
    </div>
  );
}

我还有一个Chat.js“ / chat”页面,在该页面中收集数据并启动与套接字的通信。

import React, { useState, useEffect } from "react";
import queryString from 'query-string';
import io from "socket.io-client";

import TextContainer from '../TextContainer/TextContainer';
import Messages from '../Messages/Messages';
import InfoBar from '../InfoBar/InfoBar';
import Input from '../Input/Input';

import './Chat.css';

let socket;

const Chat = ({ match }) => {
  const [name, setName] = useState('');
  const [room, setRoom] = useState('');
  const [users, setUsers] = useState('');
  const [message, setMessage] = useState('');
  const [messages, setMessages] = useState([]);
  const ENDPOINT = 'http://localhost:3000/';

  useEffect(() => {
    const { name, room } = queryString.parse(location.search);

    socket = io(ENDPOINT);

    setRoom(room);
    setName(name)

    socket.emit('join', { name, room }, (error) => {
      if(error) {
        alert(error);
      }
    });
  }, [ENDPOINT, location.search]);

  useEffect(() => {
    socket.on('message', message => {
      setMessages(messages => [ ...messages, message ]);
    });

    socket.on("roomData", ({ users }) => {
      setUsers(users);
    });
}, []);

  const sendMessage = (event) => {
    event.preventDefault();

    if(message) {
      socket.emit('sendMessage', message, () => setMessage(''));
    }
  }

  return (
    <div className="outerContainer">
      <div className="container">
          <InfoBar room={room} />
          <Messages messages={messages} name={name} />
          <Input message={message} setMessage={setMessage} sendMessage={sendMessage} />
      </div>
      <TextContainer users={users}/>
    </div>
  );
}

export default Chat;

我还有一个后端chat.controller.js,可以解析来自套接字的数据:

const users = [];

const addUser = ({ id, name, room }) => {

  name = name.trim().toLowerCase();
  room = room.trim().toLowerCase();

  const existingUser = users.find((user) => user.room === room && user.name === name);

  if(!name || !room) return { error: 'Username and room are required.' };
  if(existingUser) return { error: 'Username is taken.' };

  const user = { id, name, room };

  users.push(user);

  return { user };
}

const removeUser = (id) => {
  const index = users.findIndex((user) => user.id === id);

  if(index !== -1) return users.splice(index, 1)[0];
}

const getUser = (id) => users.find((user) => user.id === id);

const getUsersInRoom = (room) => users.filter((user) => user.room === room);

export default { 
    addUser,
    removeUser,
    getUser,

此函数是从另一个文件chatcha.controller.js调用的,该文件与后端的套接字进行通信。

import chatCtrl from '../controllers/chat.controller'

export default (server) => {
  const io = require('socket.io').listen(server)
  io.on('connect', (socket) => {
    socket.on('join', ({ name, room }, callback) => {
      const { error, user } = chatCtrl.addUser({ id: socket.id, name, room });

      if(error) return callback(error);

      socket.join(user.room);

      socket.emit('message', { user: 'admin', text: `${user.name}, welcome to room ${user.room}.`});
      socket.broadcast.to(user.room).emit('message', { user: 'admin', text: `${user.name} has joined!` });

      io.to(user.room).emit('roomData', { room: user.room, users: chatCtrl.getUsersInRoom(user.room) });

      callback();
    });

    socket.on('sendMessage', (message, callback) => {
      const user = chatCtrl.getUser(socket.id);

      io.to(user.room).emit('message', { user: user.name, text: message });

      callback();
    });

    socket.on('disconnect', () => {
      const user = chatCtrl.removeUser(socket.id);

      if(user) {
        io.to(user.room).emit('message', { user: 'Admin', text: `${user.name} has left.` });
        io.to(user.room).emit('roomData', { room: user.room, users: chatCtrl.getUsersInRoom(user.room)});
      }
    })
  });
}

我的目标是想出一种方法,让用户单击我的UI中的“聊天”按钮,而不必填写表单-基本上绕过Join.js,立即路由到Chat.js。

  • 考虑到我可以在values.users.name中访问我的用户名,我觉得这应该不是一个困难的解决方案。但是,我在所有运动部件上苦苦挣扎,发现React文档不足以说明问题。

我衷心感谢您花时间阅读我的问题,并希望收到社区的回音。

0 个答案:

没有答案