or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cache-management.mdcore-data-fetching.mdglobal-configuration.mdimmutable-data.mdindex.mdinfinite-loading.mdmutations.mdsubscriptions.md

immutable-data.mddocs/

0

# Immutable Data

1

2

The `useSWRImmutable` hook is designed for static data that doesn't require revalidation, providing the same API as `useSWR` but with all revalidation options disabled.

3

4

## Capabilities

5

6

### useSWRImmutable Hook

7

8

Hook for static data that doesn't require revalidation, with all revalidation options disabled.

9

10

```typescript { .api }

11

/**

12

* Hook for static data that doesn't require revalidation

13

* @param key - Unique identifier for the request

14

* @param fetcher - Function that fetches the data, or null to disable fetching

15

* @param config - Configuration options (revalidation options are disabled)

16

* @returns SWRResponse object identical to useSWR

17

*/

18

function useSWRImmutable<Data = any, Error = any>(

19

key: Key,

20

fetcher?: Fetcher<Data, Key> | null,

21

config?: SWRConfiguration<Data, Error>

22

): SWRResponse<Data, Error>;

23

```

24

25

**Usage Examples:**

26

27

```typescript

28

import useSWRImmutable from "swr/immutable";

29

30

// Static configuration data

31

const { data: config } = useSWRImmutable("/api/config", fetcher);

32

33

// User profile (changes infrequently)

34

const { data: profile } = useSWRImmutable(

35

userId ? `/api/users/${userId}/profile` : null,

36

fetcher

37

);

38

39

// Application constants

40

const { data: constants } = useSWRImmutable("/api/constants", fetcher);

41

42

// Translation data

43

const { data: translations } = useSWRImmutable(

44

`/api/i18n/${locale}`,

45

fetcher

46

);

47

48

// One-time data fetch

49

const { data: report } = useSWRImmutable(

50

`/api/reports/${reportId}`,

51

fetcher

52

);

53

```

54

55

### Behavior Differences

56

57

`useSWRImmutable` automatically disables all revalidation options:

58

59

```typescript { .api }

60

// These options are automatically set to false:

61

const defaultConfig = {

62

revalidateOnFocus: false,

63

revalidateIfStale: false,

64

revalidateOnReconnect: false,

65

// All other options work normally

66

};

67

```

68

69

**Comparison with useSWR:**

70

71

```typescript

72

// Regular useSWR - will revalidate on focus, reconnect, etc.

73

const { data: dynamicData } = useSWR("/api/dynamic", fetcher);

74

75

// useSWRImmutable - will never revalidate automatically

76

const { data: staticData } = useSWRImmutable("/api/static", fetcher);

77

78

// Equivalent to useSWR with manual revalidation disabled

79

const { data: manualStatic } = useSWR("/api/static", fetcher, {

80

revalidateOnFocus: false,

81

revalidateIfStale: false,

82

revalidateOnReconnect: false,

83

});

84

```

85

86

### When to Use useSWRImmutable

87

88

**Perfect for:**

89

90

```typescript

91

// Application configuration

92

const { data: appConfig } = useSWRImmutable("/api/app-config", fetcher);

93

94

// Feature flags (when they don't change during session)

95

const { data: features } = useSWRImmutable("/api/feature-flags", fetcher);

96

97

// Static content (documentation, help text)

98

const { data: helpContent } = useSWRImmutable(

99

`/api/help/${section}`,

100

fetcher

101

);

102

103

// Cached computed results

104

const { data: expensiveComputation } = useSWRImmutable(

105

["compute", complexParams],

106

([, params]) => performExpensiveComputation(params)

107

);

108

109

// Historical data (doesn't change)

110

const { data: historicalData } = useSWRImmutable(

111

`/api/history/${date}`,

112

fetcher

113

);

114

115

// Reference data (currencies, countries, etc.)

116

const { data: currencies } = useSWRImmutable("/api/currencies", fetcher);

117

const { data: countries } = useSWRImmutable("/api/countries", fetcher);

118

```

119

120

### Manual Revalidation

121

122

Even with `useSWRImmutable`, you can still trigger manual revalidation:

123

124

```typescript

125

function StaticDataComponent() {

126

const { data, mutate } = useSWRImmutable("/api/config", fetcher);

127

128

// Manual refresh (still works)

129

const handleRefresh = () => {

130

mutate(); // This will revalidate even with useSWRImmutable

131

};

132

133

return (

134

<div>

135

<div>Config: {JSON.stringify(data)}</div>

136

<button onClick={handleRefresh}>Force Refresh</button>

137

</div>

138

);

139

}

140

141

// Global manual revalidation

142

import { mutate } from "swr";

143

144

const refreshStaticData = () => {

145

mutate("/api/config"); // Works even if using useSWRImmutable

146

};

147

```

148

149

### Advanced Patterns

150

151

**Conditional Immutability:**

152

153

```typescript

154

function DataComponent({ isStatic }: { isStatic: boolean }) {

155

// Choose hook based on data nature

156

const hook = isStatic ? useSWRImmutable : useSWR;

157

const { data, error } = hook("/api/data", fetcher);

158

159

return <div>{data ? JSON.stringify(data) : "Loading..."}</div>;

160

}

161

```

162

163

**Cache Warming:**

164

165

```typescript

166

function App() {

167

// Pre-load static data that will be needed throughout the app

168

useSWRImmutable("/api/config", fetcher);

169

useSWRImmutable("/api/user-permissions", fetcher);

170

useSWRImmutable("/api/feature-flags", fetcher);

171

172

return <Router />;

173

}

174

175

// Later components can access the cached data instantly

176

function FeatureComponent() {

177

const { data: features } = useSWRImmutable("/api/feature-flags", fetcher);

178

// This will return cached data immediately, no loading state

179

180

return features?.newFeature ? <NewFeature /> : <OldFeature />;

181

}

182

```

183

184

**Locale-Specific Data:**

185

186

```typescript

187

function LocalizedApp() {

188

const [locale, setLocale] = useState("en");

189

190

// Translation data is immutable per locale

191

const { data: translations } = useSWRImmutable(

192

`/api/i18n/${locale}`,

193

fetcher

194

);

195

196

// When locale changes, a new request is made but data for each locale

197

// is cached permanently (until page refresh)

198

199

return (

200

<div>

201

<select value={locale} onChange={(e) => setLocale(e.target.value)}>

202

<option value="en">English</option>

203

<option value="es">Spanish</option>

204

<option value="fr">French</option>

205

</select>

206

207

<div>{translations ? <TranslatedContent translations={translations} /> : "Loading..."}</div>

208

</div>

209

);

210

}

211

```

212

213

**Static Resource Loading:**

214

215

```typescript

216

// Hook for loading static resources

217

function useStaticResource<T>(path: string): T | undefined {

218

const { data } = useSWRImmutable(

219

path,

220

async (path: string) => {

221

const response = await fetch(path);

222

if (!response.ok) {

223

throw new Error(`Failed to load ${path}`);

224

}

225

return response.json();

226

}

227

);

228

229

return data;

230

}

231

232

// Usage

233

function DocumentationPage() {

234

const schema = useStaticResource<JsonSchema>("/schemas/api.json");

235

const examples = useStaticResource<Examples>("/examples/api-examples.json");

236

237

if (!schema || !examples) {

238

return <div>Loading documentation...</div>;

239

}

240

241

return <ApiDocumentation schema={schema} examples={examples} />;

242

}

243

```

244

245

**Performance Optimization:**

246

247

```typescript

248

// Use useSWRImmutable for expensive computations that don't change

249

function ExpensiveChart({ dataParams }: { dataParams: DataParams }) {

250

const { data: processedData } = useSWRImmutable(

251

["processed-data", dataParams],

252

([, params]) => {

253

// This expensive computation will only run once per unique params

254

return processLargeDataset(params);

255

}

256

);

257

258

return <Chart data={processedData} />;

259

}

260

261

// Heavy external API calls for static data

262

function CountryInfo({ countryCode }: { countryCode: string }) {

263

const { data: countryDetails } = useSWRImmutable(

264

`country-${countryCode}`,

265

() => fetchCountryFromExternalAPI(countryCode), // Expensive external call

266

{

267

// Even though it's immutable, we might want error retry

268

shouldRetryOnError: true,

269

errorRetryInterval: 1000,

270

}

271

);

272

273

return <div>{countryDetails?.name}</div>;

274

}

275

```

276

277

### Best Practices

278

279

**When to choose useSWRImmutable over useSWR:**

280

281

1. **Static Configuration**: App config, feature flags, constants

282

2. **Reference Data**: Countries, currencies, time zones

283

3. **Historical Data**: Past reports, archived content

284

4. **Heavy Computations**: Results that are expensive to recalculate

285

5. **One-time Fetches**: Data that definitely won't change during session

286

6. **Static Content**: Help docs, terms of service, static pages

287

288

**When to stick with useSWR:**

289

290

1. **User Data**: Profiles, preferences (even if updated infrequently)

291

2. **Live Data**: Anything that might change during user session

292

3. **Collaborative Data**: Content that other users might modify

293

4. **Time-Sensitive Data**: Even if updates are rare

294

5. **Error Recovery**: When you need automatic revalidation on reconnect

295

296

**Performance Considerations:**

297

298

```typescript

299

// Good: Static data that never changes

300

const { data: constants } = useSWRImmutable("/api/constants", fetcher);

301

302

// Good: Heavy computation with stable inputs

303

const { data: result } = useSWRImmutable(

304

["heavy-calc", stableParams],

305

computeExpensiveResult

306

);

307

308

// Avoid: Data that might change (use useSWR instead)

309

// const { data: userNotifications } = useSWRImmutable("/api/notifications", fetcher);

310

311

// Avoid: External APIs that might return different data

312

// const { data: weather } = useSWRImmutable("/api/weather", fetcher);

313

```