聊天应用程序如何知道用户何时发送消息以重新呈现?

时间:2021-03-31 02:50:50

标签: javascript mysql node.js reactjs express

我需要使用 websockets 吗?我正在使用 MySQL 创建一个 React 应用程序,我希望它基本上是一个聊天应用程序。我可以让它在我使用的浏览器中重新呈现,但如果我打开另一个选项卡并输入一条消息,我的应用程序将不会重新呈现。有什么简单的方法可以解决这个问题,或者我应该使用 websockets 吗?这是我的代码。

app.js

 useEffect(() => {
    console.log('use effect is in use.');
    fetch(`http://localhost:4000/getallmessages`)
      .then((data) => data.json())
      .then((messages) => {
        setGetAllMessages(messages);
      })
      .catch((err) => {
        console.log(err);
      });
  }, []);

  return (
    <div className={classes.AppContainer}>
      {loggedIn ? (
        <>
          {loginMessage ? setIntervalMessage() : null}
          {loginMessage ? (
            <h3 className={classes.SuccessMessage}>
              {loginMessage.successMessage}
            </h3>
          ) : null}

          <Chatroom
            user={user}
            getAllMessages={getAllMessages}
            setGetAllMessages={setGetAllMessages}
          />
        </>
      ) : (
        <>
          <Login
            setSignInPassword={setSignInPassword}
            setSignInUsername={setSignInUsername}
            login={login}
            signInPassword={signInPassword}
            signInUsername={signInUsername}
          />

          {loginErrorMessage ? (
            <p className={classes.ErrorMessage}>
              {loginErrorMessage.errorMessage}
            </p>
          ) : null}

          <Signup
            setUsername={setUsername}
            setPassword={setPassword}
            createUsername={createUsername}
            username={username}
            password={password}
          />
          {signup ? <p>{signup.message}</p> : null}
          {signupError ? <p>{signupError.errors[0].msg}</p> : <p></p>}
        </>
      )}
    </div>
  );
};

这里是聊天室组件

const Chatroom = ({ user, getAllMessages, setGetAllMessages }) => {
  const [getMessages, setGetMessages] = useState();
  const [userMessage, setUserMessage] = useState('');
  const [getAllUsers, setGetAllUsers] = useState();
  const [flag, setFlag] = useState(false);
  const [randomColor, setRandomColor] = useState(
    Math.floor(Math.random() * 16777215).toString(16)
  );

  const messagesEndRef = useRef(null);

  const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  };

  useEffect(() => {
    fetch(`http://localhost:4000/getallusers`)
      .then((data) => data.json())
      .then((users) => {
        console.log('-----ALL USERS------', users);
        setGetAllUsers(users);
      })
      .catch((err) => console.log(err));
  }, []);

  useEffect(() => {
    fetch(`http://localhost:4000/getuser/${user.username}/${user.id}`)
      .then((response) => response.json())
      .then((data) => {
        setGetMessages(data.message);
      })
      .catch((err) => {
        console.log(err);
      });
  }, []);

  const sendMessage = (e) => {
    setUserMessage('');

    e.preventDefault();

    const body = {
      userMessage: userMessage,
      user: user.username,
      userId: user.id,
    };

    fetch(`http://localhost:4000/sendmessage/${user.id}`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(body),
    })
      .then((data) => {
        return data.json();
      })
      .then((message) => {
        console.log('success', message);
        setFlag(true);
      })
      .catch((err) => {
        console.log(err);
      });
  };

  const getUserInput = (e) => {
    setUserMessage(e.target.value);
  };

  useEffect(() => {
    if (flag === true);
    fetch(`http://localhost:4000/getallmessages`)
      .then((data) => data.json())
      .then((messages) => {
        setGetAllMessages(messages);
        setFlag(false);
      })
      .catch((err) => {
        console.log(err);
      });
  }, [flag]);

  useEffect(() => {
    scrollToBottom();
  }, [getAllMessages, flag]);

  if (
    user === undefined ||
    getMessages === undefined ||
    getAllMessages === undefined ||
    getAllUsers === undefined
  )
    return <p>loading..</p>;

  return (
    <div className={classes.ChatroomContainer}>
      <h1>Welcome {user ? user.username : 'Elita'}</h1>
      <div className={classes.ChatroomBox}>
        {getAllMessages.message.map((allMessages) => (
          <div key={allMessages.id}>
            <p>
              {getAllUsers.messages.map((user) =>
                user.id === allMessages.userId ? (
                  <span
                    key={user.id}
                    className={classes.UsernameColor}
                    //create a random color to differenciate users.
                    style={{
                      color: '#' + randomColor,
                    }}
                  >
                    {user.username} :
                  </span>
                ) : (
                  ''
                )
              )}
              {allMessages.message}
            </p>
            <div ref={messagesEndRef} />
          </div>
        ))}

        <input type='hidden' name={user ? user.username : ''} />
        <input type='hidden' name={user ? user.id : ''} />
      </div>
      <div className={classes.SendMessageUI}>
        <input
          type='text'
          name='userMessage'
          placeholder='hi eli ;)'
          onChange={(e) => getUserInput(e)}
          onKeyDownCapture={(e) => (e.keyCode === 13 ? sendMessage(e) : null)}
          value={userMessage}
        ></input>
        <button onClick={sendMessage}>Send</button>
      </div>
    </div>
  );
};

最后使用 node.js 后端

路线

router.get('/getallusers', chatroomController.getAllUsers);
router.get('/getallmessages', chatroomController.getAllMesssages);
router.get('/getuser/:user/:userid', chatroomController.getUser);

router.post(
  '/createuser',
  body('username')
    .isLength({ min: 3 })
    .withMessage('oops username must be at least 3 characters in length'),
  body('password')
    .isLength({ min: 5 })
    .withMessage('oops password must have 5 characters'),
  authController.createUser
);

router.post(
  '/signin',
  body('signInUsername')
    .isLength({ min: 3 })
    .withMessage('oops username needs at least 5 characters'),
  body('signInPassword')
    .isLength({ min: 5 })
    .withMessage('oops password needs to be at least 5 characters'),
  authController.postSignin
);

router.post('/sendmessage/:userid', chatroomController.postSendMessage);

和控制器

exports.getAllUsers = async (req, res, next) => {
  User.findAll()
    .then((user) => {
      if (!user) {
        res.json({ message: 'oops no users' });
        return next();
      }
      res.json({ messages: user });
      console.log(user);
    })
    .catch((err) => {
      console.log(err);
    });
};

exports.getAllMesssages = (req, res, next) => {
  Message.findAll()
    .then((messages) => {
      if (!messages) {
        console.log('oops no messages');
        res.json({ message: 'oops no messages' });
        return next();
      }
      console.log(messages);
      res.json({ message: messages });
    })
    .catch((err) => {
      console.log(err);
    });
};

exports.getUser = (req, res, next) => {
  Message.findAll({ where: { userId: req.params.userid } })
    .then((userAndMessage) => {
      if (!userAndMessage) {
        res.json({ message: 'oops something went wrong.' });
        return next();
      }
      console.log(userAndMessage);
      res.json({ message: userAndMessage, user: userAndMessage });
    })
    .catch((err) => {
      console.log(err);
      return err;
    });
};

exports.postSendMessage = (req, res, next) => {
  const message = req.body.userMessage;
  const userId = req.params.userid;
  console.log(req.params);
  Message.create({
    message: message,
    userId: userId,
  })
    .then((message) => {
      console.log(message);
      res.json({ message: 'success!', message: message });
    })
    .catch((err) => {
      console.log(err);
      res.json({ message: 'something went wrong.' });
    });
};

1 个答案:

答案 0 :(得分:0)

我建议使用网络套接字或 MQTT,通过 MQTT,您需要连接到像 Mosquitto 或 CloudMQTT 这样的代理才能订阅主题。然后,您可以在 React 应用程序中实现逻辑以在消息到达时更新状态,这将导致页面重新呈现。如果您采用这种方法并建立客户,我会选择Paho

这是一个给你一个想法的片段:

const [message, setMessage] = useState("");

const client = new Paho.MQTT.Client(location.hostname, Number(location.port), "clientId");

// set callback handlers
client.onMessageArrived = onMessageArrived;
 
// called when a message arrives
const onMessageArrived = (message) => {
    setMessage(message.payloadstring);
}
相关问题