WebSocket + React 的简单 Demo

逻辑撷汐人
• 阅读 2652

WebSocket + React 的简单 Demo

关于需求

简单接受服务端信息的功能

前端需求分析

  • 可接受服务端信息
  • 可关闭会话
  • 可重启会话

知识需求

  • 一点点 TS + React
  • 一点点 node +express
  • 一点点 websocket

关于最简 demo

  • 前端仅实现 启动 WebSocket接受会话 为关键
  • 服务端 node 会实现计时器里实现不断发送信息的任务
import React, { useState, useRef, useLayoutEffect, useEffect } from 'react';

const App = () => {
  const ws = useRef<WebSocket | null>(null);
  const [message, setMessage] = useState('');
  //启动
  useLayoutEffect(() => {
    ws.current = new WebSocket('ws://localhost:7070');
    ws.current.onmessage = e => {
      setMessage(e.data);
    };
    return () => {
      ws.current?.close();
    };
  }, [ws]);


  return (
    <div className='App'>
      <div className='container'>
          {message}
      </div>
    </div>
  );
};

关于主动会话与主动开关机制

熟悉一下 相关方法

  • WebSocket.send() 发送会话
  • WebSocket.close() 关闭会话
  • WebSocket.onmessage() 接受会话

在例子里,组件渲染的时候已经开始了 WebSocket 链接,根据需求是要主动开启 WebSocket 链接的,例子关键 WebSocket 需要提取出来

const webSocketInit = useCallback(() => {
    if (!ws.current) {
      ws.current = new WebSocket('ws://localhost:7070');
    }
  }, [ws]);

React 是喜欢不可变数据的,这里使用了 useCallback 包裹了相关方法,以达到可主动链接且不会造成多次渲染的目的

在组件生命周期外,或许需要关闭会话,达到浏览器资源释放的问题

useLayoutEffect(()=>{
  // do somting
  return ()=>{
    ws.current?.close();
  }
},[ws])

React Hooks Api 内建议这样释放资源,同理可以在 commpoent api 内使用 xxx 释放资源

关于最终展示的代码

个人认为在最终代码内,最好有日志打印,使用 Hooks api 来监听 WebSocket 的状态去打印日志会显得很费劲且繁琐不堪,得益于 WebSocket 自有的 api 就可以做到很好的日志答应


import React, { useState, useRef, useLayoutEffect, useCallback } from 'react';
import Header from './components/header';
import './App.less';

const App = () => {
  const ws = useRef<WebSocket | null>(null);
  const [message, setMessage] = useState('');
  const [readyState, setReadyState] = useState('正在链接中');
  const [rdNum, SetRdNum] = useState<number>(0);

  /**
   * 伪随机函数,测试用
   *  */
  const getRandomInt = useCallback(() => {
    SetRdNum(Math.floor(Math.random() * Math.floor(999)));
  }, []);

  const webSocketInit = useCallback(() => {
    const stateArr = [
      '正在链接中',
      '已经链接并且可以通讯',
      '连接正在关闭',
      '连接已关闭或者没有链接成功',
    ];
    if (!ws.current || ws.current.readyState === 3) {
      ws.current = new WebSocket('ws://localhost:7070');
      ws.current.onopen = _e =>
        setReadyState(stateArr[ws.current?.readyState ?? 0]);
      ws.current.onclose = _e =>
        setReadyState(stateArr[ws.current?.readyState ?? 0]);
      ws.current.onerror = e =>
        setReadyState(stateArr[ws.current?.readyState ?? 0]);
      ws.current.onmessage = e => {
        setMessage(e.data);
      };
    }
  }, [ws]);

  /**
   * 初始化 WebSocket
   * 且使用 WebSocket 原声方法获取信息
   *  */
  useLayoutEffect(() => {
    getRandomInt();
    webSocketInit();
    return () => {
      ws.current?.close();
    };
  }, [ws, getRandomInt, webSocketInit]);

  console.log('ws.readyState', ws.current?.readyState);

  return (
    <div className='App'>
      <Header status={readyState} />
      <div className='container'>
        <div>{message}</div>
        {/* <div>{readyState}</div> */}
        <div
          onClick={() => {
            ws.current?.close();
          }}>
          Clone
        </div>
        <div
          onClick={() => {
            getRandomInt();
            webSocketInit();
          }}>
          start
        </div>
        <div
          onClick={() => {
            if (ws.current?.readyState !== 1) {
              console.log('尚未链接成功');
              setMessage('正在链接');
              return;
            }
            ws.current?.send(rdNum.toString());
          }}>
          ID:{rdNum}
        </div>
      </div>
    </div>
  );
};

export default App;

关于 QA

Q:为什么不实用 socket.io?

简单需求下,没必要下载一个库,学习 WebSocket 也有利于理解 socket 源码,或许后期也会在项目使用 socket.io

Q:为什么要在 function commopent 内里做 WebSocket 初始化?

可以肯定,在外初始化肯定是更好阅读与理解的,如下例子:

import React from 'react';

const ws = new WebSocket('ws://loaclhost:7070');

const App = () => {
  // do ing...
};

考虑到后续的 WebSocket 状态均需要在 function commopent 内显示,所以最终选择了在内初始化的选择,目前还没看到优秀的在外且可接受状态的优秀例子

Q:为什么不能直接使用 WebSocket.readyState 的状态来打印状态?

WebSocket.readyState 实际上并没有跟着返回消息或者操作更新了状态,需要主动获取来感知状态的更新

关于小结

本文或许没多到新鲜感,属于个人笔记的流水线文章

感谢各位阅读!


关于借鉴

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
梦
5年前
微信小程序new Date()转换时间异常问题
微信小程序苹果手机页面上显示时间异常,安卓机正常问题image(https://imghelloworld.osscnbeijing.aliyuncs.com/imgs/b691e1230e2f15efbd81fe11ef734d4f.png)错误代码vardate'2021030617:00:00'vardateT
Wesley13 Wesley13
4年前
VBox 启动虚拟机失败
在Vbox(5.0.8版本)启动Ubuntu的虚拟机时,遇到错误信息:NtCreateFile(\\Device\\VBoxDrvStub)failed:0xc000000034STATUS\_OBJECT\_NAME\_NOT\_FOUND(0retries) (rc101)Makesurethekern
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
4年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
4年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这