加载中...

前端实现简单的sse封装(React hook Vue3)

什么是SSE?

所谓的SSE(Sever-Sent Event),就是浏览器向服务器发送了一个HTTP请求,保持长连接,服务器不断单向地向浏览器推送“信息”,这么做是为了节省网络资源,不用一直发请求,建立新连接。

  • 优点:SSE和WebSocket相比,最大的优势是便利,服务端不需要第三方组件,开发难度低,SSE和轮询相比它不用处理很多请求,不用每次建立新连接,延迟低。
  • 缺点:如果客户端有很多需要保持很多长连接,这回占用大量内存和连接数。

封装简单的SSE,以React hook为例。 可参考简单的websocket封装

1. 新建sse.ts文件

import {useState, useRef, useEffect} from ''react''

const useSSE = (url: string) => {
    const source = useRef<EventSource | null>(null)
    //接收到的sse数据
    const [sseData, setSseData] = useState({})

    // sse状态
    const [sseReadyState, setSseReadyState] = useState({
        key: 0,
        value: ''正在链接中'',
    })

    const creatSource = () => {
        const stateArr = [
            {key: 0, value: ''正在链接中''},
            {key: 1, value: ''已经链接并且可以通讯''},
            {key: 2, value: ''连接已关闭或者没有链接成功''},
        ]

        try {
            source.current = new EventSource(url)
            source.current.onopen = (_e) => {
                setSseReadyState(stateArr[source.current?.readyState ?? 0])
            }

            source.current.onerror = (e) => {
                setSseReadyState(stateArr[source.current?.readyState ?? 0])
            }
            source.current.onmessage = (e) => {
                setSseData({...JSON.parse(e.data)})
            }
        } catch (error) {
            console.log(error)
        }
    }

    const sourceInit = () => {
        if (!source.current || source.current.readyState === 2) {
            creatSource()
        }
    }

    //  关闭 WebSocket
    const closeSource = () => {
        source.current?.close()
    }

    //重连
    const reconnectSSE = () => {
        try {
            closeSource()
            source.current = null
            creatSource()
        } catch (e) {
            console.log(e)
        }
    }

    useEffect(() => {
        sourceInit()
    },[])

    return {
        sseData,
        sseReadyState,
        closeSource,
        reconnectSSE,
    }
}
export default useSSE
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 这里一共暴露出四个参数。分别是 sseData(接收到的 sse数据)、sseReadyState(当前 sse状态)、closeSource(关闭 sse)、reconnectSSE(重连)。通过这几个简单的参数能够覆盖一般场景的需要。下面代码为使用方法:
import React, { useState, useEffect } from ''react''
import useWebsocket from ''../../tools/webSocket''
export default function () {
	const {sseData,sseReadyState, closeSource,reconnectSSE} = useSSE(url)

	useEffect(() => {
        console.log( ''当前状态'',sseReadyState)
    },[sseReadyState])

	useEffect(() => {
        console.log( ''接收到的数据'',sseData)
    }, [sseData])
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

使用vue3实现

import { ref } from "vue";

const useSSE = (url: string) => {
  const source = ref<EventSource | null>(null);

  //接收到的sse数据
  const sseData = ref({});

  // sse状态
  const readyState = ref({ key: 0, value: "正在链接中" });

  const creatSource = () => {
    const stateArr = [
      { key: 0, value: "正在链接中" },
      { key: 1, value: "已经链接并且可以通讯" },
      { key: 2, value: "连接已关闭或者没有链接成功" },
    ];

    try {
      source.value= new EventSource(url);
      source.value.onopen = (e) => {
        readyState.value = stateArr[source.value?.readyState ?? 0];
      };

      source.value.onerror = (e) => {
        readyState.value = stateArr[source.value?.readyState ?? 0];
      };
      source.value.onmessage = (e) => {
        e.data && (sseData.value = { ...JSON.parse(e.data) });
      };
    } catch (error) {
      console.log(error);
    }
  };

  const sourceInit = () => {
    if (!source.value|| source.value.readyState === 2) {
      creatSource();
    }
  };

  //  关闭 WebSocket
  const closeSource = () => {
    source.value?.close();
  };

  //重连
  const reconnectSSE = () => {
    try {
      closeSource();
      source.value= null;
      creatSource();
    } catch (e) {
      console.log(e);
    }
  };

  return {
    sseData,
    readyState,
    sourceInit,
    closeSource,
    reconnectSSE,
  };
};
export default useSSE;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66