or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-hooks.mdconcurrency-helpers.mdcore-hooks.mdfamily-patterns.mdindex.mdloadable-system.mdmemory-management.mdroot-provider.mdstate-definition.md

state-definition.mddocs/

0

# State Definition

1

2

Core functions for defining atoms and selectors that form the foundation of Recoil's state graph. Atoms represent units of state, while selectors represent derived state or computations.

3

4

## Capabilities

5

6

### Atom Definition

7

8

Creates a unit of state that components can read from and write to.

9

10

```typescript { .api }

11

/**

12

* Creates an atom, which represents a piece of writeable state

13

*/

14

function atom<T>(options: AtomOptions<T>): RecoilState<T>;

15

16

type AtomOptions<T> = {

17

/** Unique string identifying this atom */

18

key: string;

19

/** Default value for the atom */

20

default?: T | RecoilValue<T> | Promise<T> | Loadable<T> | WrappedValue<T>;

21

/** Array of effects to run when atom is first used */

22

effects?: ReadonlyArray<AtomEffect<T>>;

23

/** Allow direct mutation of atom values (use with caution) */

24

dangerouslyAllowMutability?: boolean;

25

};

26

```

27

28

**Usage Examples:**

29

30

```typescript

31

import { atom } from 'recoil';

32

33

// Simple atom with primitive default

34

const countState = atom({

35

key: 'countState',

36

default: 0,

37

});

38

39

// Atom with object default

40

const userState = atom({

41

key: 'userState',

42

default: {

43

id: null,

44

name: '',

45

email: '',

46

},

47

});

48

49

// Atom with async default

50

const userProfileState = atom({

51

key: 'userProfileState',

52

default: fetch('/api/user').then(res => res.json()),

53

});

54

55

// Atom with effects

56

const persistedState = atom({

57

key: 'persistedState',

58

default: '',

59

effects: [

60

({setSelf, onSet}) => {

61

// Initialize from localStorage

62

const saved = localStorage.getItem('persistedState');

63

if (saved != null) {

64

setSelf(JSON.parse(saved));

65

}

66

67

// Save to localStorage on changes

68

onSet((newValue) => {

69

localStorage.setItem('persistedState', JSON.stringify(newValue));

70

});

71

},

72

],

73

});

74

```

75

76

### Atom Value Wrapping

77

78

Utility for preventing automatic unwrapping of values in atoms and selectors.

79

80

```typescript { .api }

81

namespace atom {

82

/**

83

* Wraps a value to prevent unwrapping by Recoil

84

*/

85

function value<T>(value: T): WrappedValue<T>;

86

}

87

88

interface WrappedValue<T> {

89

readonly [WrappedValue_OPAQUE]: true;

90

}

91

```

92

93

**Usage Examples:**

94

95

```typescript

96

import { atom } from 'recoil';

97

98

// Prevent unwrapping of promises

99

const promiseState = atom({

100

key: 'promiseState',

101

default: atom.value(Promise.resolve('value')), // Promise won't be unwrapped

102

});

103

104

// Prevent unwrapping of Recoil values

105

const wrappedAtomState = atom({

106

key: 'wrappedAtomState',

107

default: atom.value(someOtherAtom), // Atom won't be read

108

});

109

```

110

111

### Selector Definition

112

113

Creates derived state that can depend on atoms or other selectors.

114

115

```typescript { .api }

116

/**

117

* Creates a selector which represents derived state

118

*/

119

function selector<T>(options: ReadWriteSelectorOptions<T>): RecoilState<T>;

120

function selector<T>(options: ReadOnlySelectorOptions<T>): RecoilValueReadOnly<T>;

121

122

interface ReadOnlySelectorOptions<T> {

123

/** Unique string identifying this selector */

124

key: string;

125

/** Function that computes the selector's value */

126

get: (opts: {

127

get: GetRecoilValue;

128

getCallback: GetCallback;

129

}) => T | RecoilValue<T> | Promise<T> | Loadable<T> | WrappedValue<T>;

130

/** Cache policy for this selector */

131

cachePolicy_UNSTABLE?: CachePolicyWithoutEquality;

132

/** Allow direct mutation of selector values (use with caution) */

133

dangerouslyAllowMutability?: boolean;

134

}

135

136

interface ReadWriteSelectorOptions<T> extends ReadOnlySelectorOptions<T> {

137

/** Function that handles setting the selector's value */

138

set: (opts: {

139

set: SetRecoilState;

140

get: GetRecoilValue;

141

reset: ResetRecoilState;

142

}, newValue: T | DefaultValue) => void;

143

}

144

```

145

146

**Usage Examples:**

147

148

```typescript

149

import { atom, selector, DefaultValue } from 'recoil';

150

151

const textState = atom({

152

key: 'textState',

153

default: '',

154

});

155

156

// Read-only selector

157

const charCountState = selector({

158

key: 'charCountState',

159

get: ({get}) => {

160

const text = get(textState);

161

return text.length;

162

},

163

});

164

165

// Async selector

166

const userNameState = selector({

167

key: 'userNameState',

168

get: async ({get}) => {

169

const userID = get(currentUserIDState);

170

const response = await fetch(`/api/users/${userID}`);

171

return response.json();

172

},

173

});

174

175

// Read-write selector

176

const tempFahrenheit = selector({

177

key: 'tempFahrenheit',

178

get: ({get}) => {

179

const tempCelsius = get(tempCelsiusState);

180

return (tempCelsius * 9) / 5 + 32;

181

},

182

set: ({set}, newValue) => {

183

const tempCelsius = ((newValue as number) - 32) * 5 / 9;

184

set(tempCelsiusState, tempCelsius);

185

},

186

});

187

188

// Selector with error handling

189

const safeDataState = selector({

190

key: 'safeDataState',

191

get: async ({get}) => {

192

try {

193

const data = await get(asyncDataState);

194

return data;

195

} catch (error) {

196

return { error: error.message };

197

}

198

},

199

});

200

```

201

202

### Selector Value Wrapping

203

204

Utility for preventing automatic unwrapping of values in selectors.

205

206

```typescript { .api }

207

namespace selector {

208

/**

209

* Wraps a value to prevent unwrapping by Recoil

210

*/

211

function value<T>(value: T): WrappedValue<T>;

212

}

213

```

214

215

### Convenience Selectors

216

217

Pre-built selectors for common use cases.

218

219

```typescript { .api }

220

/**

221

* Returns a selector that always has a constant value

222

*/

223

function constSelector<T extends SerializableParam>(constant: T): RecoilValueReadOnly<T>;

224

225

/**

226

* Returns a selector which is always in the provided error state

227

*/

228

function errorSelector(message: string): RecoilValueReadOnly<never>;

229

230

/**

231

* Casts a selector to be a read-only selector

232

*/

233

function readOnlySelector<T>(atom: RecoilValue<T>): RecoilValueReadOnly<T>;

234

```

235

236

**Usage Examples:**

237

238

```typescript

239

import { constSelector, errorSelector, readOnlySelector } from 'recoil';

240

241

// Constant selector

242

const appVersionState = constSelector('1.0.0');

243

244

// Error selector for testing

245

const errorState = errorSelector('This always errors');

246

247

// Read-only wrapper

248

const readOnlyUserState = readOnlySelector(userState);

249

```

250

251

### Atom Effects

252

253

System for adding side effects to atoms when they are first used.

254

255

```typescript { .api }

256

type AtomEffect<T> = (param: {

257

node: RecoilState<T>;

258

storeID: StoreID;

259

trigger: 'set' | 'get';

260

setSelf: (param: T | DefaultValue | Promise<T | DefaultValue> | WrappedValue<T> |

261

((param: T | DefaultValue) => T | DefaultValue | WrappedValue<T>)) => void;

262

resetSelf: () => void;

263

onSet: (param: (newValue: T, oldValue: T | DefaultValue, isReset: boolean) => void) => void;

264

getPromise: <S>(recoilValue: RecoilValue<S>) => Promise<S>;

265

getLoadable: <S>(recoilValue: RecoilValue<S>) => Loadable<S>;

266

getInfo_UNSTABLE: <S>(recoilValue: RecoilValue<S>) => RecoilStateInfo<S>;

267

}) => void | (() => void);

268

```

269

270

**Usage Examples:**

271

272

```typescript

273

import { atom } from 'recoil';

274

275

// Persistence effect

276

const localStorageEffect = (key: string) => ({setSelf, onSet}) => {

277

const savedValue = localStorage.getItem(key);

278

if (savedValue != null) {

279

setSelf(JSON.parse(savedValue));

280

}

281

282

onSet((newValue, _, isReset) => {

283

isReset

284

? localStorage.removeItem(key)

285

: localStorage.setItem(key, JSON.stringify(newValue));

286

});

287

};

288

289

// Logging effect

290

const loggingEffect = ({onSet, node}) => {

291

onSet((newValue, oldValue) => {

292

console.log(`${node.key} changed from`, oldValue, 'to', newValue);

293

});

294

};

295

296

// Atom with effects

297

const trackedState = atom({

298

key: 'trackedState',

299

default: '',

300

effects: [

301

localStorageEffect('tracked-state'),

302

loggingEffect,

303

],

304

});

305

```

306

307

## Cache Policies

308

309

Configuration for selector result caching and eviction.

310

311

```typescript { .api }

312

type EvictionPolicy = 'lru' | 'keep-all' | 'most-recent';

313

314

type CachePolicyWithoutEquality =

315

| {eviction: 'lru', maxSize: number}

316

| {eviction: 'keep-all'}

317

| {eviction: 'most-recent'};

318

```