or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdcore-observables.mdhelper-functions.mdindex.mdpersistence.mdreact-integration.md
tile.json

react-integration.mddocs/

0

# React Integration

1

2

React hooks and components for building reactive user interfaces with Legend State. The React integration provides optimized rendering with minimal re-renders through fine-grained dependency tracking.

3

4

## Capabilities

5

6

### React Hooks

7

8

#### Observable Hook

9

10

Creates and manages observables within React components.

11

12

```typescript { .api }

13

/**

14

* Creates an observable state within a React component

15

* @param initialValue - Initial value, function returning value, or async function

16

* @returns Observable instance tied to component lifecycle

17

*/

18

function useObservable<T>(initialValue?: T | (() => T) | (() => Promise<T>)): Observable<T>;

19

```

20

21

#### Observe Effect Hook

22

23

Observes observable changes and runs effects when dependencies update.

24

25

```typescript { .api }

26

/**

27

* Observes changes and runs effect function when dependencies change

28

* @param selector - Function that accesses observables to track

29

* @param effect - Effect function to run on changes

30

*/

31

function useObserveEffect<T>(

32

selector: () => T,

33

effect: (value: T) => void

34

): void;

35

36

/**

37

* Alternative observe hook for direct observable observation

38

* @param selector - Function accessing observables

39

* @param reaction - Reaction function for changes

40

*/

41

function useObserve<T>(

42

selector: () => T,

43

reaction: (value: T) => void

44

): void;

45

```

46

47

#### Selector Hook

48

49

Subscribes to observable values with automatic re-rendering.

50

51

```typescript { .api }

52

/**

53

* Subscribes to observable selector with automatic re-rendering

54

* @param selector - Function selecting observable values

55

* @returns Current value from selector

56

*/

57

function useSelector<T>(selector: () => T): T;

58

```

59

60

#### Computed Hook

61

62

Creates computed values within React components.

63

64

```typescript { .api }

65

/**

66

* Creates a computed value within React component

67

* @param compute - Function to compute the value

68

* @returns Computed value that updates automatically

69

*/

70

function useComputed<T>(compute: () => T): T;

71

```

72

73

#### When Hook

74

75

Provides Promise-based waiting within React components.

76

77

```typescript { .api }

78

/**

79

* Returns Promise that resolves when predicate becomes truthy

80

* @param predicate - Function to evaluate

81

* @param effect - Optional effect to run when resolved

82

* @returns Promise resolving to truthy value

83

*/

84

function useWhen<T>(

85

predicate: () => T,

86

effect?: (value: T) => void

87

): Promise<T>;

88

```

89

90

#### Observable Reducer Hook

91

92

Provides Redux-like pattern with observables.

93

94

```typescript { .api }

95

/**

96

* Creates observable state with reducer pattern

97

* @param reducer - Reducer function for state updates

98

* @param initialState - Initial state value

99

* @returns Tuple of observable state and dispatch function

100

*/

101

function useObservableReducer<T, A>(

102

reducer: (state: T, action: A) => T,

103

initialState: T

104

): [Observable<T>, (action: A) => void];

105

```

106

107

### Lifecycle Hooks

108

109

Utility hooks for component lifecycle management.

110

111

```typescript { .api }

112

/**

113

* Runs effect only once on component mount

114

* @param effect - Effect function to run on mount

115

*/

116

function useEffectOnce(effect: () => void | (() => void)): void;

117

118

/**

119

* Runs effect on component mount

120

* @param effect - Effect function to run on mount

121

*/

122

function useMount(effect: () => void): void;

123

124

/**

125

* Runs effect on component unmount

126

* @param effect - Effect function to run on unmount

127

*/

128

function useUnmount(effect: () => void): void;

129

130

/**

131

* Returns whether component is currently mounted

132

* @returns Boolean indicating mount status

133

*/

134

function useIsMounted(): boolean;

135

```

136

137

### React Components

138

139

#### Reactive Components

140

141

Higher-order components that automatically re-render when observables change.

142

143

```typescript { .api }

144

/**

145

* Makes any HTML element reactive to observable changes

146

* Generic component that works with all HTML elements

147

*/

148

declare const Reactive: {

149

[K in keyof JSX.IntrinsicElements]: React.ComponentType<

150

JSX.IntrinsicElements[K] & {

151

$key?: Observable<string | number>;

152

}

153

>;

154

};

155

156

/**

157

* HOC to make any component reactive to observable changes

158

* @param Component - Component to make reactive

159

* @returns Reactive version of the component

160

*/

161

function reactive<T extends React.ComponentType<any>>(Component: T): T;

162

163

/**

164

* Configuration for reactive system

165

* @param config - Configuration options

166

*/

167

function configureReactive(config: ReactiveConfig): void;

168

169

interface ReactiveConfig {

170

/** Whether to track changes automatically */

171

autoTrack?: boolean;

172

/** Whether to use direct rendering optimizations */

173

directRender?: boolean;

174

}

175

```

176

177

#### Control Flow Components

178

179

Components for conditional rendering and iteration.

180

181

```typescript { .api }

182

/**

183

* Conditional rendering component

184

* @param props.if - Selector condition to evaluate

185

* @param props.ifReady - Alternative selector for ready state

186

* @param props.else - Optional fallback content

187

* @param props.children - Content to render when condition is true

188

*/

189

function Show<T>(props: {

190

if?: Selector<T>;

191

ifReady?: Selector<T>;

192

else?: React.ReactNode | (() => React.ReactNode);

193

wrap?: React.ComponentType;

194

children: React.ReactNode | ((value?: T) => React.ReactNode);

195

}): JSX.Element;

196

197

/**

198

* Switch/case rendering component

199

* @param props.value - Observable value to switch on

200

* @param props.children - Switch cases as children

201

*/

202

function Switch<T>(props: {

203

value: Observable<T> | (() => T);

204

children: React.ReactNode;

205

}): JSX.Element;

206

207

/**

208

* Array iteration component with optimized rendering

209

* @param props.each - Observable array, object, or Map to iterate

210

* @param props.item - Component for rendering each item

211

* @param props.children - Alternative render function for each item

212

* @param props.optimized - Whether to use optimization

213

*/

214

function For<T, TProps = {}>(props: {

215

each?: ObservableReadable<T[] | Record<any, T> | Map<any, T>>;

216

item?: React.ComponentType<{ item$: Observable<T>; id?: string } & TProps>;

217

itemProps?: TProps;

218

children?: (item: Observable<T>, id: string | undefined) => React.ReactElement;

219

optimized?: boolean;

220

sortValues?: (A: T, B: T, AKey: string, BKey: string) => number;

221

}): JSX.Element;

222

223

/**

224

* Memoized component wrapper

225

* @param props.children - Function returning content to memoize

226

*/

227

function Memo<T>(props: {

228

children: () => React.ReactNode;

229

}): JSX.Element;

230

231

/**

232

* Computed value component

233

* @param props.children - Function returning computed content

234

*/

235

function Computed<T>(props: {

236

children: () => React.ReactNode;

237

}): JSX.Element;

238

```

239

240

#### Provider Components

241

242

Context providers for pause/resume functionality.

243

244

```typescript { .api }

245

/**

246

* Provides pause context to child components

247

* @param paused - Whether to pause reactive updates

248

* @returns Provider component

249

*/

250

function usePauseProvider(paused: boolean): React.ComponentType<{

251

children: React.ReactNode;

252

}>;

253

```

254

255

### Extended React Hooks

256

257

Additional hooks for common UI patterns and integrations.

258

259

```typescript { .api }

260

/**

261

* Hook for persisted observable state

262

* @param key - Storage key for persistence

263

* @param initialValue - Initial value if not persisted

264

* @returns Persisted observable

265

*/

266

function usePersistedObservable<T>(

267

key: string,

268

initialValue?: T

269

): Observable<T>;

270

271

/**

272

* Hook for observable queries with loading/error states

273

* @param queryFn - Function returning Promise of data

274

* @param options - Query configuration options

275

* @returns Observable query state

276

*/

277

function useObservableQuery<T>(

278

queryFn: () => Promise<T>,

279

options?: QueryOptions

280

): ObservableQuery<T>;

281

282

interface QueryOptions {

283

enabled?: boolean;

284

refetchInterval?: number;

285

staleTime?: number;

286

}

287

288

interface ObservableQuery<T> {

289

data: Observable<T | undefined>;

290

error: Observable<Error | undefined>;

291

isLoading: Observable<boolean>;

292

isError: Observable<boolean>;

293

refetch: () => Promise<void>;

294

}

295

296

/**

297

* Hook for fetch operations with observable state

298

* @param url - URL to fetch

299

* @param options - Fetch options

300

* @returns Observable fetch state

301

*/

302

function useFetch<T>(

303

url: string,

304

options?: RequestInit

305

): ObservableFetch<T>;

306

307

interface ObservableFetch<T> {

308

data: Observable<T | undefined>;

309

error: Observable<Error | undefined>;

310

loading: Observable<boolean>;

311

}

312

313

/**

314

* Hook for hover state tracking

315

* @returns Hover state and ref

316

*/

317

function useHover(): [Observable<boolean>, React.RefObject<HTMLElement>];

318

319

/**

320

* Hook for element measurements

321

* @returns Measurements and ref

322

*/

323

function useMeasure(): [

324

Observable<{ width: number; height: number }>,

325

React.RefObject<HTMLElement>

326

];

327

328

/**

329

* Creates observable from any hook

330

* @param hookFn - Hook function to make observable

331

* @returns Hook that returns observable

332

*/

333

function createObservableHook<T>(hookFn: () => T): () => Observable<T>;

334

```

335

336

**Usage Examples:**

337

338

```typescript

339

import React from "react";

340

import { observable } from "@legendapp/state";

341

import {

342

useObservable,

343

useSelector,

344

Reactive,

345

Show,

346

For

347

} from "@legendapp/state/react";

348

349

// Component with local observable state

350

function TodoApp() {

351

const todos$ = useObservable([

352

{ id: 1, text: "Learn Legend State", done: false },

353

{ id: 2, text: "Build awesome app", done: false }

354

]);

355

356

const newTodo$ = useObservable("");

357

358

const addTodo = () => {

359

const text = newTodo$.get().trim();

360

if (text) {

361

todos$.push({

362

id: Date.now(),

363

text,

364

done: false

365

});

366

newTodo$.set("");

367

}

368

};

369

370

return (

371

<div>

372

<input

373

value={useSelector(() => newTodo$.get())}

374

onChange={e => newTodo$.set(e.target.value)}

375

onKeyPress={e => e.key === 'Enter' && addTodo()}

376

/>

377

<button onClick={addTodo}>Add Todo</button>

378

379

<For each={todos$} item={(todo$, index$) => (

380

<Reactive.div key={todo$.id.get()}>

381

<input

382

type="checkbox"

383

checked={todo$.done.get()}

384

onChange={e => todo$.done.set(e.target.checked)}

385

/>

386

<span style={{

387

textDecoration: todo$.done.get() ? 'line-through' : 'none'

388

}}>

389

{todo$.text.get()}

390

</span>

391

<button onClick={() => todos$.splice(index$.get(), 1)}>

392

Delete

393

</button>

394

</Reactive.div>

395

)} />

396

397

<Show if={() => todos$.get().length === 0}>

398

<p>No todos yet!</p>

399

</Show>

400

</div>

401

);

402

}

403

404

// Global state example

405

const appState$ = observable({

406

user: null,

407

theme: "light",

408

notifications: []

409

});

410

411

function Header() {

412

const theme = useSelector(() => appState$.theme.get());

413

414

return (

415

<Reactive.header className={`header theme-${theme}`}>

416

<Show

417

if={() => appState$.user.get()}

418

else={<button>Login</button>}

419

>

420

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

421

</Show>

422

</Reactive.header>

423

);

424

}

425

```