Documentation Index Fetch the complete documentation index at: https://mintlify.com/statelyai/xstate/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The useSelector composition function subscribes to an actor and returns a derived value from its snapshot. It only triggers updates when the selected value changes.
function useSelector < TActor , T >(
actor : TActor | Ref < TActor >,
selector : ( snapshot : SnapshotFrom < TActor >) => T ,
compare ?: ( a : T , b : T ) => boolean
) : Ref < T >
Basic Usage
Select Context Value
Select State Value
Complex Selection
< script setup >
import { useActor , useSelector } from '@xstate/vue' ;
import { createMachine } from 'xstate' ;
const machine = createMachine ({
context: { count: 0 , name: 'Alice' },
// ...
});
const { actorRef } = useActor ( machine );
// Only re-renders when count changes
const count = useSelector ( actorRef , ( state ) => state . context . count );
// Only re-renders when name changes
const name = useSelector ( actorRef , ( state ) => state . context . name );
</ script >
< template >
< div >
< p > Count: {{ count }} </ p >
< p > Name: {{ name }} </ p >
</ div >
</ template >
Custom Comparison
By default, useSelector uses strict equality (===) to compare values. Provide a custom comparison function for complex objects:
Shallow Comparison
Deep Comparison
Array Comparison
< script setup >
import { useActor , useSelector } from '@xstate/vue' ;
import { myMachine } from './myMachine' ;
const { actorRef } = useActor ( myMachine );
function shallowEqual ( a , b ) {
if ( a === b ) return true ;
if ( ! a || ! b ) return false ;
const keysA = Object . keys ( a );
const keysB = Object . keys ( b );
if ( keysA . length !== keysB . length ) return false ;
return keysA . every ( key => a [ key ] === b [ key ]);
}
const user = useSelector (
actorRef ,
( state ) => state . context . user ,
shallowEqual
);
</ script >
Reactive Actor Reference
You can pass a reactive Ref<Actor> to useSelector:
< script setup >
import { ref } from 'vue' ;
import { useActor , useSelector } from '@xstate/vue' ;
import { machine1 , machine2 } from './machines' ;
const { actorRef : actor1 } = useActor ( machine1 );
const { actorRef : actor2 } = useActor ( machine2 );
const currentActor = ref ( actor1 );
// Automatically subscribes to the current actor
const value = useSelector (
currentActor ,
( state ) => state . context . value
);
function switchActor () {
currentActor . value = actor2 ;
}
</ script >
< template >
< div >
< p > Value: {{ value }} </ p >
< button @click = "switchActor" > Switch Actor </ button >
</ div >
</ template >
Use useSelector to optimize rendering by only subscribing to specific parts of state:
< script setup >
import { useActor , useSelector } from '@xstate/vue' ;
import { largeMachine } from './largeMachine' ;
const { actorRef } = useActor ( largeMachine );
// Component only re-renders when username changes,
// not when other context values change
const username = useSelector (
actorRef ,
( state ) => state . context . user . name
);
// Component only re-renders when this specific state is active
const isEditMode = useSelector (
actorRef ,
( state ) => state . matches ({ editing: 'user' })
);
</ script >
< template >
< div >
< h1 > {{ username }} </ h1 >
< form v-if = "isEditMode" >
<!-- Edit form -->
</ form >
</ div >
</ template >
Multiple Selectors
Create multiple selectors for different values:
< script setup >
import { useActor , useSelector } from '@xstate/vue' ;
import { dashboardMachine } from './dashboardMachine' ;
const { actorRef , send } = useActor ( dashboardMachine );
const userName = useSelector (
actorRef ,
( state ) => state . context . user . name
);
const notifications = useSelector (
actorRef ,
( state ) => state . context . notifications
);
const unreadCount = useSelector (
actorRef ,
( state ) => state . context . notifications . filter ( n => ! n . read ). length
);
const currentPage = useSelector (
actorRef ,
( state ) => state . value
);
</ script >
< template >
< div >
< header >
< span > {{ userName }} </ span >
< span v-if = "unreadCount > 0" >
{{ unreadCount }} new notifications
</ span >
</ header >
< main >
< p > Current page: {{ currentPage }} </ p >
</ main >
</ div >
</ template >
Selecting from Spawned Actors
Use useSelector with actors spawned from a parent machine:
< script setup >
import { useActor , useSelector } from '@xstate/vue' ;
import { computed } from 'vue' ;
import { parentMachine } from './parentMachine' ;
const { actorRef : parent } = useActor ( parentMachine );
// Get spawned child actor
const childActor = useSelector (
parent ,
( state ) => state . context . childActor
);
// Select from child if it exists
const childValue = computed (() => {
if ( ! childActor . value ) return null ;
return childActor . value . getSnapshot (). context . value ;
});
</ script >
< template >
< div >
< div v-if = "childActor" >
Child value: {{ childValue }}
</ div >
</ div >
</ template >
TypeScript
The selector function is fully typed:
import { setup } from 'xstate' ;
import { useActor , useSelector } from '@xstate/vue' ;
import type { Ref } from 'vue' ;
interface User {
id : string ;
name : string ;
email : string ;
}
const machine = setup ({
types: {
context: {} as {
user : User ;
count : number ;
}
}
}). createMachine ({
context: {
user: { id: '1' , name: 'Alice' , email: 'alice@example.com' },
count: 0
}
});
const { actorRef } = useActor ( machine );
// TypeScript infers the return type
const userName : Ref < string > = useSelector (
actorRef ,
( state ) => state . context . user . name
);
const userEmail : Ref < string > = useSelector (
actorRef ,
( state ) => state . context . user . email
);
Implementation Details
The useSelector hook:
Creates a shallow ref for the selected value
Uses Vue’s watch to monitor the actor ref
Subscribes to actor changes on mount
Compares new selected values using the comparison function
Only updates the ref when the comparison returns false
Automatically unsubscribes on cleanup
useActor Create and manage actors with reactive snapshots
Vue Integration Back to Vue integration overview