or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

context-utilities.mddocs/

0

# Context Utilities

1

2

The context utilities provide a way to share XState actors across React component trees using React Context. This is ideal for global state management and avoiding prop drilling.

3

4

## createActorContext

5

6

Creates a React context with provider and context-bound hooks for sharing an XState actor across components.

7

8

```typescript { .api }

9

function createActorContext<TLogic extends AnyActorLogic>(

10

actorLogic: TLogic,

11

actorOptions?: ActorOptions<TLogic>

12

): {

13

useSelector: <T>(

14

selector: (snapshot: SnapshotFrom<TLogic>) => T,

15

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

16

) => T;

17

useActorRef: () => Actor<TLogic>;

18

Provider: React.ComponentType<{

19

children: React.ReactNode;

20

options?: ActorOptions<TLogic>;

21

logic?: TLogic;

22

}>;

23

};

24

```

25

26

### Parameters

27

28

- `actorLogic`: The XState actor logic to be shared

29

- `actorOptions`: Default actor configuration options

30

31

### Returns

32

33

An object containing:

34

- `useSelector`: Context-bound selector hook

35

- `useActorRef`: Context-bound actor reference hook

36

- `Provider`: React component to provide the actor context

37

38

### Usage Example

39

40

```typescript

41

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

42

import { createMachine, assign } from "xstate";

43

44

// Define your machine

45

const authMachine = createMachine({

46

id: "auth",

47

initial: "loggedOut",

48

context: {

49

user: null,

50

token: null

51

},

52

states: {

53

loggedOut: {

54

on: {

55

LOGIN: {

56

target: "loggedIn",

57

actions: assign({

58

user: ({ event }) => event.user,

59

token: ({ event }) => event.token

60

})

61

}

62

}

63

},

64

loggedIn: {

65

on: {

66

LOGOUT: {

67

target: "loggedOut",

68

actions: assign({

69

user: null,

70

token: null

71

})

72

}

73

}

74

}

75

}

76

});

77

78

// Create the context

79

const AuthContext = createActorContext(authMachine);

80

81

// App component with provider

82

function App() {

83

return (

84

<AuthContext.Provider>

85

<Navigation />

86

<MainContent />

87

</AuthContext.Provider>

88

);

89

}

90

91

// Components that use the context

92

function Navigation() {

93

const user = AuthContext.useSelector((state) => state.context.user);

94

const isLoggedIn = AuthContext.useSelector((state) => state.matches("loggedIn"));

95

const authActor = AuthContext.useActorRef();

96

97

if (!isLoggedIn) {

98

return (

99

<nav>

100

<button onClick={() => authActor.send({

101

type: "LOGIN",

102

user: { name: "John" },

103

token: "abc123"

104

})}>

105

Login

106

</button>

107

</nav>

108

);

109

}

110

111

return (

112

<nav>

113

<span>Welcome, {user.name}!</span>

114

<button onClick={() => authActor.send({ type: "LOGOUT" })}>

115

Logout

116

</button>

117

</nav>

118

);

119

}

120

121

function MainContent() {

122

const isLoggedIn = AuthContext.useSelector((state) => state.matches("loggedIn"));

123

124

return (

125

<main>

126

{isLoggedIn ? <Dashboard /> : <LoginPrompt />}

127

</main>

128

);

129

}

130

```

131

132

## Provider Component

133

134

The Provider component created by `createActorContext` accepts the following props:

135

136

```typescript { .api }

137

interface ProviderProps<TLogic extends AnyActorLogic> {

138

children: React.ReactNode;

139

options?: ActorOptions<TLogic>;

140

logic?: TLogic;

141

/** @deprecated Use `logic` instead. */

142

machine?: never;

143

}

144

```

145

146

### Props

147

148

- `children`: React children to receive the context

149

- `options`: Optional actor configuration options (overrides defaults)

150

- `logic`: Optional different actor logic (overrides default)

151

152

### Usage with Custom Options

153

154

```typescript

155

function App() {

156

return (

157

<AuthContext.Provider

158

options={{

159

input: { apiUrl: "https://api.example.com" }

160

}}

161

>

162

<AppContent />

163

</AuthContext.Provider>

164

);

165

}

166

```

167

168

### Usage with Different Logic

169

170

```typescript

171

const devAuthMachine = createMachine({

172

// Development version with mock data

173

});

174

175

function App() {

176

const isDevelopment = process.env.NODE_ENV === "development";

177

178

return (

179

<AuthContext.Provider

180

logic={isDevelopment ? devAuthMachine : authMachine}

181

>

182

<AppContent />

183

</AuthContext.Provider>

184

);

185

}

186

```

187

188

## Context-bound Hooks

189

190

### useSelector

191

192

The context-bound `useSelector` hook works identically to the standalone version but automatically uses the actor from context.

193

194

```typescript { .api }

195

const contextUseSelector: <T>(

196

selector: (snapshot: SnapshotFrom<TLogic>) => T,

197

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

198

) => T;

199

```

200

201

### useActorRef

202

203

The context-bound `useActorRef` hook returns the actor reference from context.

204

205

```typescript { .api }

206

const contextUseActorRef: () => Actor<TLogic>;

207

```

208

209

## Error Handling

210

211

The context hooks will throw an error if used outside of their corresponding Provider:

212

213

```typescript

214

function ComponentOutsideProvider() {

215

// This will throw an error

216

const user = AuthContext.useSelector((state) => state.context.user);

217

// Error: You used a hook from "ActorProvider" but it's not inside a <ActorProvider> component.

218

}

219

```

220

221

## Multiple Contexts

222

223

You can create and use multiple actor contexts in the same application:

224

225

```typescript

226

const AuthContext = createActorContext(authMachine);

227

const ThemeContext = createActorContext(themeMachine);

228

const CartContext = createActorContext(cartMachine);

229

230

function App() {

231

return (

232

<AuthContext.Provider>

233

<ThemeContext.Provider>

234

<CartContext.Provider>

235

<AppContent />

236

</CartContext.Provider>

237

</ThemeContext.Provider>

238

</AuthContext.Provider>

239

);

240

}

241

242

function AppContent() {

243

const user = AuthContext.useSelector((state) => state.context.user);

244

const theme = ThemeContext.useSelector((state) => state.context.theme);

245

const cartItems = CartContext.useSelector((state) => state.context.items);

246

247

// Use all three contexts...

248

}

249

```

250

251

## Common Patterns

252

253

### Combining with Custom Hooks

254

255

```typescript

256

// Custom hook for auth operations

257

function useAuth() {

258

const user = AuthContext.useSelector((state) => state.context.user);

259

const isLoggedIn = AuthContext.useSelector((state) => state.matches("loggedIn"));

260

const authActor = AuthContext.useActorRef();

261

262

const login = useCallback((credentials) => {

263

authActor.send({ type: "LOGIN", ...credentials });

264

}, [authActor]);

265

266

const logout = useCallback(() => {

267

authActor.send({ type: "LOGOUT" });

268

}, [authActor]);

269

270

return { user, isLoggedIn, login, logout };

271

}

272

```

273

274

### Performance Optimization

275

276

```typescript

277

// Memoize selectors for complex computations

278

const memoizedSelector = useMemo(

279

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

280

[]

281

);

282

283

const result = AuthContext.useSelector(memoizedSelector);

284

```

285

286

### Conditional Context Usage

287

288

```typescript

289

function FeatureComponent({ useGlobalState }: { useGlobalState: boolean }) {

290

if (useGlobalState) {

291

const data = GlobalContext.useSelector((state) => state.context.data);

292

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

293

}

294

295

// Use local state instead

296

const [localData] = useState("local");

297

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

298

}

299

```