Some hooks to make it easy to use nats.ws in React:
// nats client:
const nc = useNats()
// simple subscription callback:
useNatsSubscription('chat', onMessage)
Some hooks to make it easy to use nats.ws in React:
// nats client:
const nc = useNats()
// simple subscription callback:
useNatsSubscription('chat', onMessage)
| // A very basic chatroom example: | |
| import { JSONCodec, Msg } from 'nats.ws' | |
| import { FormEvent, useState } from 'react' | |
| import './App.css' | |
| import { useNats, useNatsSubscription } from './useNats' | |
| const natsSubject = 'chat' | |
| const sc = JSONCodec() | |
| type ChatMsg = { | |
| handle: string | |
| msg: string | |
| } | |
| function App() { | |
| const [handle, setHandle] = useState('') | |
| const [msg, setMsg] = useState('') | |
| const [log, setLog] = useState<ChatMsg[]>([]) | |
| const nc = useNats() | |
| useNatsSubscription(natsSubject, onMessage) | |
| async function onMessage(msg: Msg) { | |
| const data = sc.decode(msg.data) as ChatMsg | |
| setLog((old) => [...old, data]) | |
| } | |
| async function sendMessage(e: FormEvent) { | |
| e.preventDefault() | |
| nc!.publish(natsSubject, sc.encode({ handle, msg })) | |
| setMsg('') | |
| } | |
| return ( | |
| <div className="App"> | |
| <div className="chat-log"> | |
| {log.map((c, idx) => ( | |
| <div className="chat-msg" key={idx}> | |
| <b>{c.handle}</b>: {c.msg} | |
| </div> | |
| ))} | |
| </div> | |
| <hr /> | |
| <form onSubmit={sendMessage}> | |
| <input | |
| type="text" | |
| value={handle} | |
| onChange={(e) => setHandle(e.target.value)} | |
| placeholder="handle" | |
| required | |
| /> | |
| <input | |
| type="text" | |
| value={msg} | |
| onChange={(e) => setMsg(e.target.value)} | |
| placeholder="Say something..." | |
| required | |
| /> | |
| <button>Send</button> | |
| </form> | |
| </div> | |
| ) | |
| } | |
| export default App |
| // a basic example of using SWR (https://swr.vercel.app/) | |
| // to do request / reply to NATS | |
| import { JSONCodec } from 'nats.ws' | |
| import useSWR from 'swr' | |
| import { natsClientPromise } from './useNats' | |
| const sc = JSONCodec() | |
| type TimeResponse = { | |
| now: string | |
| } | |
| async function natsRequest(subj: string) { | |
| console.time(`natsRequest:${subj}`) | |
| const nc = await natsClientPromise | |
| const resp = await nc.request(subj) | |
| console.timeEnd(`natsRequest:${subj}`) | |
| return resp | |
| } | |
| export function Clock() { | |
| const { data, error } = useSWR('time', natsRequest, { | |
| refreshInterval: 1000, | |
| }) | |
| if (error) return <div>Error: {error.message}</div> | |
| if (!data) return <div>loading...</div> | |
| const t = sc.decode(data.data) as TimeResponse | |
| const motd = data.headers?.get('motd') | |
| return ( | |
| <div> | |
| <b>server time: {t.now}</b> | |
| {motd && <em>motd: {motd}</em>} | |
| </div> | |
| ) | |
| } |
| import { connect, headers, JSONCodec } from 'nats' | |
| const sc = JSONCodec() | |
| export async function clockServer() { | |
| const nc = await connect({ | |
| servers: 'localhost:4222', | |
| }) | |
| const sub = nc.subscribe('time') | |
| console.log(`listening for ${sub.getSubject()} requests...`) | |
| for await (const m of sub) { | |
| const now = new Date().toISOString() | |
| const h = headers() | |
| h.append('motd', `gotta get down on Friday`) | |
| m.respond(sc.encode({ now }), { headers: h }) | |
| } | |
| } |
| import { connect, Msg, NatsConnection, NatsError } from 'nats.ws' | |
| import { useState, useEffect } from 'react' | |
| export const natsClientPromise = connect({ servers: 'ws://localhost:4242' }) | |
| export function useNats() { | |
| const [nats, setNats] = useState<NatsConnection | null>(null) | |
| useEffect(() => { | |
| if (!nats) { | |
| natsClientPromise | |
| .then((nc) => { | |
| setNats(nc) | |
| }) | |
| .catch((err) => console.error('connect failed', err)) | |
| } | |
| }, []) | |
| return nats | |
| } | |
| type SuccessCallback = (msg: Msg) => Promise<void> | |
| export function useNatsSubscription(subj: string, onMessage: SuccessCallback) { | |
| const nc = useNats() | |
| useEffect(() => { | |
| if (!nc) return | |
| const sub = nc.subscribe(subj, { | |
| callback: function (err: NatsError | null, msg: Msg) { | |
| if (err) { | |
| console.error(err) | |
| } else { | |
| onMessage(msg) | |
| } | |
| }, | |
| }) | |
| return () => { | |
| sub.unsubscribe() | |
| } | |
| }, [nc]) | |
| } |