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]) | |
} |