Method UseSyncExternalStore
- Namespace
- Velvet
- Assembly
- Velvet.Docs.dll
UseSyncExternalStore<T>(Func<Action, Action>, Func<T>)
Subscribes to a store Velvet does not own and returns its current snapshot — the counterpart of React's
useSyncExternalStore(subscribe, getSnapshot). Must be used inside Render() only.
public static T UseSyncExternalStore<T>(Func<Action, Action> subscribe, Func<T> getSnapshot)
Parameters
subscribeFunc<Action, Action>Registers a store-change callback and returns its unsubscribe action. Must not be null.
getSnapshotFunc<T>Returns the store's current snapshot. Must not be null.
Returns
- T
The store snapshot this render observes.
Type Parameters
TSnapshot type.
Remarks
getSnapshot must return the same value, compared with Object.is, on every call
while the store has not changed: cache the snapshot instead of building a new one per read. A store-change
notification re-renders the component when getSnapshot then returns a value that is not
Object.is-equal to the one it last committed, or throws. A render that returns another snapshot than
the previous one, or that subscribes, checks the snapshot again in its passive effects, so a snapshot built
afresh per read re-renders the component after every render until the scheduler's update-depth limit drops
the update and logs an error. In the Editor, a hook whose two consecutive reads in one render differ logs an
error once.
subscribe receives the callback to invoke when the store changes and returns the action
that unsubscribes it. It is called in the passive effects of the first commit, and again, after the previous
subscription is removed, in those of a commit whose render passed a subscribe that is
not System.Delegate.Equals(object) to the previous one, or that follows a call that threw. A render
whose body throws or suspends, and an attempt a render-phase update re-runs, subscribe and unsubscribe
nothing, and the StrictMode diagnostic render never calls it. A method group on the same instance compares equal across renders; a lambda capturing a
local is a new closure each render and re-subscribes on each later commit, as an inline subscribe function
does in React. Unmounting removes the subscription. A change the store makes between the render and the
subscription, or while subscribe runs, re-renders the component once the subscription
is made.
The callback must be invoked on the Unity main thread: invoked from another thread, it throws
System.InvalidOperationException to its invoker and schedules nothing. The re-render it schedules
takes the Urgent lane and never the Transition lane, including when the store is mutated inside
startTransition, and the scheduler flushes it from the main thread's posted work instead of waiting
for its next frame-boundary callback. The scheduler's resume of a parked time-sliced pass flushes such a
re-render first, so readers the pass committed in an earlier slice show the changed snapshot before the next
slice renders it.
Within one batch drain pass, readers passing equal getSnapshot delegates observe the
snapshot the pass's first read pinned, as readers of one store do through
UseStore<TStore, TSel>(Store<TStore>, Func<TStore, TSel>, IEqualityComparer<TSel>?); the next pass, the delayed tier's included, pins afresh. A render
outside a drain reads the live snapshot. A render that returns a pin the store has moved past asks for a
re-render in its passive effects.