useEvent
Preact hook for listening to NUI messages from FiveM Lua.
useEvent is a Preact hook that listens for window.postMessage events from the FiveM Lua client. It filters messages by a type field and calls your handler with the event data.
Import
import { useEvent } from '@repo/ui/utils/useEvent'Signature
function useEvent<T = unknown>(
type: string,
handler: (data: T) => void
): voidParameters
| Parameter | Type | Description |
|---|---|---|
type | string | The message type to listen for (matches the type field in SendNUIMessage) |
handler | (data: T) => void | Callback invoked when a matching message is received |
Usage
import { useEvent } from '@repo/ui/utils/useEvent'
function Notification() {
const [message, setMessage] = useState('')
useEvent<string>('showNotification', (data) => {
setMessage(data)
})
return <div>{message}</div>
}Corresponding Lua Code
Send messages to the NUI from your Lua client:
SendNUIMessage({
type = 'showNotification',
data = 'Hello from Lua!'
})Message Format
The hook expects messages in this format:
interface NuiMessageData<T> {
type: string // Matched against the `type` parameter
data: T // Passed to the handler
}This matches FiveM's SendNUIMessage format, where you pass a table with type and data fields.
How It Works
- The hook stores the latest handler in a ref to avoid stale closures
- Attaches a
messageevent listener towindow - Filters events by matching
event.data.typewith the providedtypestring - Calls the handler with
event.data.datawhen a match is found - Cleans up the event listener on unmount
The handler ref is updated on every render, so the handler always has access to the latest component state without needing to re-register the event listener.
Source
import { type RefObject, useEffect, useRef } from 'preact/compat'
interface NuiMessageData<T = unknown> {
type: string
data: T
}
type NuiHandlerSignature<T> = (data: T) => void
export const useEvent = <T = unknown>(
type: string,
handler: (data: T) => void
) => {
const savedHandler: RefObject<NuiHandlerSignature<T>> = useRef(() => {})
useEffect(() => {
savedHandler.current = handler
}, [handler])
useEffect(() => {
const eventListener = (event: MessageEvent<NuiMessageData<T>>) => {
const { type: eventAction, data } = event.data
if (savedHandler.current) {
if (eventAction === type) {
savedHandler.current(data)
}
}
}
window.addEventListener('message', eventListener)
return () => window.removeEventListener('message', eventListener)
}, [type])
}