JotaiJotai

状態
Primitive and flexible state management for React

atomWithBroadcast

atomWithBroadcast creates an atom. The atom will be shared between browser tabs and frames, similar to atomWithStorage but with the initialization limitation.

This can be useful when you want states to interact with each other without the use of localStorage. By using the BroadcastChannel API, you can enable basic communication between browsing contexts such as windows, tabs, frames, components, or iframes, and workers on the same origin. According to the MDN documentation, receiving a message during initialization is not supported in the BroadcastChannel, but if you want to support that functionality, you may need to add extra option to atomWithBroadcast, such as local storage.

import { atom } from 'jotai'
export function atomWithBroadcast<Value>(key: string, initialValue: Value) {
const baseAtom = atom(initialValue)
const listeners = new Set<(event: MessageEvent<any>) => void>()
const channel = new BroadcastChannel(key)
channel.onmessage = (event) => {
listeners.forEach((l) => l(event))
}
const broadcastAtom = atom<Value, { isEvent: boolean; value: Value }>(
(get) => get(baseAtom),
(get, set, update) => {
set(baseAtom, update.value)
if (!update.isEvent) {
channel.postMessage(get(baseAtom))
}
},
)
broadcastAtom.onMount = (setAtom) => {
const listener = (event: MessageEvent<any>) => {
setAtom({ isEvent: true, value: event.data })
}
listeners.add(listener)
return () => {
listeners.delete(listener)
}
}
const returnedAtom = atom<Value, Value>(
(get) => get(broadcastAtom),
(get, set, update) => {
set(broadcastAtom, { isEvent: false, value: update })
},
)
return returnedAtom
}
const broadAtom = atomWithBroadcast('count', 0)
const ListOfThings = () => {
const [count, setCount] = useAtom(broadAtom)
return (
<div>
{count}
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
)
}