or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

context-utilities.mdcore-hooks.mdindex.mdutility-functions.md

core-hooks.mddocs/

0

# Core Hooks

1

2

The core hooks provide the primary interface for integrating XState actors with React components. These hooks manage actor lifecycle and state synchronization automatically.

3

4

## useActor

5

6

Creates and manages an XState actor with automatic React state synchronization. Returns the current snapshot, send function, and actor reference.

7

8

```typescript { .api }

9

function useActor<TLogic extends AnyActorLogic>(

10

logic: TLogic,

11

options?: ActorOptions<TLogic> & {

12

[K in RequiredActorOptionsKeys<TLogic>]: unknown;

13

}

14

): [SnapshotFrom<TLogic>, Actor<TLogic>['send'], Actor<TLogic>];

15

```

16

17

### Parameters

18

19

- `logic`: The XState actor logic (machine, promise, observable, etc.)

20

- `options`: Optional actor configuration options

21

22

### Returns

23

24

A tuple containing:

25

- `snapshot`: Current actor snapshot/state

26

- `send`: Function to send events to the actor

27

- `actorRef`: The actor reference for direct access

28

29

### Usage Example

30

31

```typescript

32

import { useActor } from "@xstate/react";

33

import { createMachine, assign } from "xstate";

34

35

const counterMachine = createMachine({

36

id: "counter",

37

initial: "idle",

38

context: { count: 0 },

39

states: {

40

idle: {

41

on: {

42

INCREMENT: {

43

actions: assign({ count: ({ context }) => context.count + 1 })

44

}

45

}

46

}

47

}

48

});

49

50

function Counter() {

51

const [state, send, actorRef] = useActor(counterMachine);

52

53

return (

54

<div>

55

<p>Count: {state.context.count}</p>

56

<button onClick={() => send({ type: "INCREMENT" })}>

57

Increment

58

</button>

59

</div>

60

);

61

}

62

```

63

64

### Features

65

66

- Automatic actor lifecycle management (start/stop)

67

- Optimized re-rendering using `useSyncExternalStore`

68

- Development-time validation to prevent common mistakes

69

- SSR compatibility with isomorphic layout effects

70

71

## useActorRef

72

73

Creates an actor reference without automatic state subscription. Useful when you need the actor reference but don't want automatic re-renders.

74

75

```typescript { .api }

76

function useActorRef<TLogic extends AnyActorLogic>(

77

machine: TLogic,

78

options?: ActorOptions<TLogic>,

79

observerOrListener?: Observer<SnapshotFrom<TLogic>> | ((value: SnapshotFrom<TLogic>) => void)

80

): Actor<TLogic>;

81

```

82

83

### Parameters

84

85

- `machine`: The XState actor logic

86

- `options`: Optional actor configuration options

87

- `observerOrListener`: Optional observer or listener function for state changes

88

89

### Returns

90

91

The actor reference for sending events and accessing state.

92

93

### Usage Example

94

95

```typescript

96

import { useActorRef, useSelector } from "@xstate/react";

97

import { createMachine } from "xstate";

98

99

const timerMachine = createMachine({

100

id: "timer",

101

initial: "idle",

102

context: { elapsed: 0 },

103

states: {

104

idle: {

105

on: { START: "running" }

106

},

107

running: {

108

on: { STOP: "idle" }

109

}

110

}

111

});

112

113

function Timer() {

114

const actorRef = useActorRef(timerMachine);

115

const elapsed = useSelector(actorRef, (state) => state.context.elapsed);

116

const isRunning = useSelector(actorRef, (state) => state.matches("running"));

117

118

return (

119

<div>

120

<p>Elapsed: {elapsed}ms</p>

121

<button onClick={() => actorRef.send({ type: isRunning ? "STOP" : "START" })}>

122

{isRunning ? "Stop" : "Start"}

123

</button>

124

</div>

125

);

126

}

127

```

128

129

### Features

130

131

- Manual control over state subscription

132

- Optional observer for custom state change handling

133

- Actor reference persists across re-renders

134

- Supports snapshot rehydration for React Strict Mode

135

136

## useSelector

137

138

Subscribes to a specific part of an actor's state using a selector function. Optimizes re-rendering by only updating when the selected value changes.

139

140

```typescript { .api }

141

function useSelector<

142

TActor extends Pick<AnyActorRef, 'subscribe' | 'getSnapshot'> | undefined,

143

T

144

>(

145

actor: TActor,

146

selector: (

147

snapshot: TActor extends { getSnapshot(): infer TSnapshot } ? TSnapshot : undefined

148

) => T,

149

compare?: (a: T, b: T) => boolean

150

): T;

151

```

152

153

### Parameters

154

155

- `actor`: The actor reference to subscribe to (can be undefined)

156

- `selector`: Function to extract the desired value from the snapshot

157

- `compare`: Optional comparison function (defaults to `===`)

158

159

### Returns

160

161

The selected value from the actor's current snapshot.

162

163

### Usage Example

164

165

```typescript

166

import { useActorRef, useSelector } from "@xstate/react";

167

import { createMachine } from "xstate";

168

169

const appMachine = createMachine({

170

id: "app",

171

initial: "loading",

172

context: {

173

user: null,

174

posts: [],

175

error: null

176

},

177

states: {

178

loading: {

179

on: { LOADED: "idle" }

180

},

181

idle: {

182

on: { ERROR: "error" }

183

},

184

error: {}

185

}

186

});

187

188

function UserProfile() {

189

const appActor = useActorRef(appMachine);

190

191

// Only re-render when user changes

192

const user = useSelector(appActor, (state) => state.context.user);

193

194

// Only re-render when loading state changes

195

const isLoading = useSelector(appActor, (state) => state.matches("loading"));

196

197

// Custom comparison for complex objects

198

const posts = useSelector(

199

appActor,

200

(state) => state.context.posts,

201

(a, b) => a.length === b.length && a.every((post, i) => post.id === b[i].id)

202

);

203

204

if (isLoading) return <div>Loading...</div>;

205

206

return (

207

<div>

208

<h1>{user?.name}</h1>

209

<p>{posts.length} posts</p>

210

</div>

211

);

212

}

213

```

214

215

### Features

216

217

- Efficient re-rendering with custom comparison functions

218

- Works with any actor reference or undefined values

219

- Built on React's `useSyncExternalStoreWithSelector`

220

- Supports complex state selection patterns

221

222

## Common Patterns

223

224

### Conditional Actor Usage

225

226

```typescript

227

function ConditionalComponent({ shouldUseActor }: { shouldUseActor: boolean }) {

228

const [state, send] = useActor(

229

shouldUseActor ? myMachine : createMachine({ initial: "idle", states: { idle: {} } })

230

);

231

232

// Component logic...

233

}

234

```

235

236

### Actor Reference Sharing

237

238

```typescript

239

function Parent() {

240

const actorRef = useActorRef(sharedMachine);

241

242

return (

243

<div>

244

<Child1 actor={actorRef} />

245

<Child2 actor={actorRef} />

246

</div>

247

);

248

}

249

250

function Child1({ actor }: { actor: Actor<typeof sharedMachine> }) {

251

const value = useSelector(actor, (state) => state.context.someValue);

252

return <div>{value}</div>;

253

}

254

```

255

256

### Performance Optimization

257

258

```typescript

259

// Use useSelector with custom comparison for expensive operations

260

const expensiveValue = useSelector(

261

actor,

262

(state) => computeExpensiveValue(state.context.data),

263

(a, b) => a.id === b.id // Only recompute when ID changes

264

);

265

```