broadcast-channel是一个跨浏览器页签通信工具(不同的浏览器不能通信);为了方便在 react 中使用,将其封装为钩子
代码实现
pnpm i broadcast-channel
import type { BroadcastChannelOptions } from 'broadcast-channel'
import { BroadcastChannel } from 'broadcast-channel'
import { useCallback, useEffect, useRef, useState } from 'react'
export function useChannel<T = any>(
key: string,
options?: BroadcastChannelOptions & {
// 是否监听自己发送的消息
// 默认为 false
selfMonitoring?: boolean
},
) {
// 使用两个实例
// 使得当前窗口也可以接受自己发送的消息
const senderRef = useRef<BroadcastChannel<T>>()
const receiverRef = useRef<BroadcastChannel<T>>()
const [message, setMessage] = useState<T>()
useEffect(() => {
if (!key.trim()) {
throw new Error('useChannel: key is required')
}
const sender = new BroadcastChannel<T>(key, options)
const receiver = new BroadcastChannel<T>(key, options)
if (options?.selfMonitoring) {
receiver.addEventListener('message', (e) => {
setMessage(e)
})
} else {
sender.addEventListener('message', (e) => {
setMessage(e)
})
}
senderRef.current = sender
receiverRef.current = receiver
return () => {
if (senderRef.current && receiverRef.current) {
senderRef.current.close()
receiverRef.current.close()
}
}
}, [key, options])
const send = useCallback((payload: T) => {
if (!senderRef.current) return
senderRef.current.postMessage(payload)
}, [])
useEffect(() => {
return () => {
senderRef.current?.close()
receiverRef.current?.close()
}
}, [])
return [message, send] as const
}
使用
function App() {
const [msg, send] = useChannel('my-channel', { selfMonitoring: true })
useEffect(() => {
console.log('msg', msg)
}, [msg])
return (
<>
<button type='button' onClick={() => send(`${Date.now()}`)}>
send
</button>
</>
)
}