useLockOnMount
Holds a record's lock while the component is mounted and reports the lock, whether a request is in flight, and the last lock failure. A failed release reaches onLockError only. Needs a realtime data provider with lock support.
useLockOnMount takes a lock when the component mounts and releases it when it
unmounts, including a lock still being requested. <LockOnMount> is the same
session with render props or slots around it.
Signature
function useLockOnMount(options?: UseLockOnMountOptions): UseLockOnMountResult
interface UseLockOnMountOptions {
/** Defaults to the resource context. */
resource?: string;
/** Defaults to the id of the record context. */
id?: Identifier;
/** Defaults to the auth provider's identity. */
identity?: Identifier;
meta?: Record<string, unknown>;
/** Called with a failed lock or release. A new function every render never relocks. */
onLockError?: (error: Error) => void;
}
interface UseLockOnMountResult {
lock: Lock | null;
isLocking: boolean;
lockError: Error | null;
}resourceandidfall back to the resource and record contexts, so a call inside<Edit>or<Show>needs neither.identityfalls back to the auth provider's identity.- With no resource, or no id from either source, it takes no lock and reports no error.
Returns
lock is the Lock while the session holds it, and null before it has one
and after it releases. isLocking is true while a lock request is in flight,
and false on the first render, before the request starts.
lockError is the last lock that failed. A record another identity holds
arrives as a LockConflictError, whose existingLock is that lock. A failed
release is not stored here: stop() clears the session state before the release
runs, so a release that rejects reaches onLockError and nowhere else.
Changing the data provider, resource, id or identity releases the old lock, even
one still in flight, before the next is taken, so a provider never sees the new
lock ahead of the old release. A new meta object, a new authProvider or a
new onLockError does not relock: the session reads them as they were when it
was made.
The hook throws when a resource and id are present and the data provider has not
gone through realtimeDataProvider. A provider wrapped without a locks option
does not throw: its lock rejects with an error saying no LockProvider was
configured, and that lands in lockError. With no identity and no auth
provider to read one from, the lock fails with an error saying no identity is
available, which lands in lockError too.
Example
import { LockConflictError } from "@chelone/core";
import { useLockOnMount } from "@chelone/react";
export const PostEditor = ({ id }: { id: number }) => {
const { lock, isLocking, lockError } = useLockOnMount({
resource: "posts",
id,
identity: "you",
onLockError: (error) => console.error(error.message),
});
if (isLocking) return <p>Requesting the lock…</p>;
if (lockError instanceof LockConflictError)
return <p>Locked by {String(lockError.existingLock.identity)}</p>;
if (lockError) return <p>{lockError.message}</p>;
// No lock yet on the first render, and none once a release lands.
return lock ? <p>Editing as {lock.identity}</p> : null;
};<LockOnMount> reads the same three states: a Skeleton while isLocking, an
alert naming existingLock.identity for a conflict, its children once the lock
is held, and nothing otherwise.
In Vue
@chelone/vue exports the same name. resource, id and identity take
MaybeRefOrGetter, and a change releases the old lock and takes the next.
lock, isLocking and lockError are refs. With no identity to lock for, and
no auth provider to read one from, it takes nothing rather than throwing.
See the realtime guide for provider setup, the
LockProvider contract and <LockOnMount>.