0
# Specialized Memoization
1
2
Specialized memoization methods optimized for specific use cases including promises, React components, and argument serialization.
3
4
## Capabilities
5
6
### Promise Memoization
7
8
Specialized memoization for async functions and promises with automatic resolution caching.
9
10
```typescript { .api }
11
/**
12
* Promise/async function memoization with automatic resolution caching
13
* Sets isPromise: true and updateExpire: true by default
14
* @returns Moizer optimized for promise-based functions
15
*/
16
promise: Moizer<{ isPromise: true }>;
17
```
18
19
**Usage Examples:**
20
21
```typescript
22
import moize from "moize";
23
24
// API call memoization
25
const fetchUser = async (userId: string) => {
26
const response = await fetch(`/api/users/${userId}`);
27
if (!response.ok) throw new Error(`Failed to fetch user ${userId}`);
28
return response.json();
29
};
30
31
const memoizedFetchUser = moize.promise(fetchUser);
32
33
// First call - makes HTTP request
34
const user1 = await memoizedFetchUser("123");
35
36
// Second call - returns cached promise result
37
const user2 = await memoizedFetchUser("123");
38
39
// Database query memoization
40
const getUserFromDB = async (id: number) => {
41
const result = await db.query('SELECT * FROM users WHERE id = ?', [id]);
42
return result[0];
43
};
44
45
const memoizedDBQuery = moize.promise.maxAge(30000)(getUserFromDB);
46
47
// Combining with other options
48
const advancedPromiseMemoization = moize.promise
49
.maxSize(50)
50
.maxAge(60000)
51
.profile('api-calls')(fetchUser);
52
```
53
54
### React Component Memoization
55
56
Specialized memoization for React components with props-based caching.
57
58
```typescript { .api }
59
/**
60
* React component memoization based on props comparison
61
* Creates component wrapper that memoizes based on props and context
62
* @returns Moizer optimized for React components
63
*/
64
react: Moizer<{ isReact: true }>;
65
```
66
67
**Usage Examples:**
68
69
```typescript
70
import moize from "moize";
71
import React from "react";
72
73
// Basic component memoization
74
interface UserCardProps {
75
user: {
76
id: number;
77
name: string;
78
email: string;
79
};
80
theme: 'light' | 'dark';
81
}
82
83
const UserCard: React.FC<UserCardProps> = ({ user, theme }) => (
84
<div className={`user-card user-card--${theme}`}>
85
<h3>{user.name}</h3>
86
<p>{user.email}</p>
87
</div>
88
);
89
90
const MemoizedUserCard = moize.react(UserCard);
91
92
// Component with deep props comparison
93
const ComplexComponent: React.FC<{
94
data: { items: any[]; metadata: Record<string, any> };
95
config: { showDetails: boolean; sortBy: string };
96
}> = ({ data, config }) => {
97
// Complex rendering logic
98
return <div>{/* rendered content */}</div>;
99
};
100
101
const MemoizedComplexComponent = moize.react.deep(ComplexComponent);
102
103
// With additional configuration
104
const OptimizedComponent = moize.react
105
.maxSize(10) // Keep 10 different prop combinations
106
.shallow // Use shallow comparison for props
107
(UserCard);
108
109
// Functional component with hooks
110
const CounterComponent: React.FC<{ initialCount: number }> = ({ initialCount }) => {
111
const [count, setCount] = React.useState(initialCount);
112
113
return (
114
<div>
115
<span>Count: {count}</span>
116
<button onClick={() => setCount(c => c + 1)}>Increment</button>
117
</div>
118
);
119
};
120
121
const MemoizedCounter = moize.react(CounterComponent);
122
```
123
124
### useMoize Hook Pattern
125
126
Custom React hook pattern for using moize within functional components with hooks.
127
128
```typescript { .api }
129
/**
130
* Custom hook pattern for memoization within React functional components
131
* Not a built-in export - user-implemented pattern from the documentation
132
*/
133
function useMoize<T extends (...args: any[]) => any>(
134
fn: T,
135
args: Parameters<T>,
136
options?: Options<T>
137
): ReturnType<T>;
138
```
139
140
**Implementation Example:**
141
142
```typescript
143
import { useRef } from 'react';
144
import moize from 'moize';
145
146
export function useMoize(fn, args, options) {
147
const moizedFnRef = useRef(moize(fn, options));
148
149
return moizedFnRef.current(...args);
150
}
151
```
152
153
**Usage Examples:**
154
155
```typescript
156
import React from 'react';
157
import { useMoize } from './moize-hooks';
158
159
function MyComponent({ first, second, object }) {
160
// Standard usage
161
const sum = useMoize((a, b) => a + b, [first, second]);
162
163
// With options
164
const deepSum = useMoize((obj) => obj.a + obj.b, [object], {
165
isDeepEqual: true,
166
});
167
168
return (
169
<div>
170
Sum of {first} and {second} is {sum}. Sum of {object.a} and{' '}
171
{object.b} is {deepSum}.
172
</div>
173
);
174
}
175
176
// Advanced usage with complex computations
177
function DataProcessingComponent({ data, filters, sortBy }) {
178
// Expensive data processing with memoization
179
const processedData = useMoize(
180
(items, filterConfig, sort) => {
181
return items
182
.filter(item => filterConfig.active ? item.status === 'active' : true)
183
.filter(item => filterConfig.category ? item.category === filterConfig.category : true)
184
.sort((a, b) => sort === 'name' ? a.name.localeCompare(b.name) : a.id - b.id);
185
},
186
[data, filters, sortBy],
187
{
188
isDeepEqual: true,
189
maxSize: 10,
190
profileName: 'data-processing'
191
}
192
);
193
194
// Complex calculation with custom equality
195
const aggregatedStats = useMoize(
196
(items) => ({
197
total: items.length,
198
active: items.filter(item => item.status === 'active').length,
199
categories: [...new Set(items.map(item => item.category))].length,
200
avgValue: items.reduce((sum, item) => sum + item.value, 0) / items.length
201
}),
202
[processedData],
203
{
204
maxAge: 30000, // 30 second TTL
205
isShallowEqual: true
206
}
207
);
208
209
return (
210
<div>
211
<h3>Processed Data ({processedData.length} items)</h3>
212
<div>Stats: {aggregatedStats.active} active, {aggregatedStats.categories} categories</div>
213
{/* Render processed data */}
214
</div>
215
);
216
}
217
```
218
219
### Serialization-based Memoization
220
221
Memoization using argument serialization for complex cache key generation.
222
223
```typescript { .api }
224
/**
225
* Serialization-based memoization using default JSON serialization
226
* Converts arguments to strings for cache key comparison
227
* @returns Moizer with serialization enabled
228
*/
229
serialize: Moizer<{ isSerialized: true }>;
230
231
/**
232
* Serialization-based memoization with custom serializer
233
* @param serializer Custom function to serialize cache keys
234
* @returns Moizer with custom serialization
235
*/
236
serializeWith<Serializer extends Serialize>(
237
serializer: Serializer
238
): Moizer<{ isSerialized: true; serializer: Serializer }>;
239
240
type Serialize = (key: Key) => string[];
241
type Key<Arg extends any = any> = Arg[];
242
```
243
244
**Usage Examples:**
245
246
```typescript
247
import moize from "moize";
248
249
// Default JSON serialization
250
const processComplexObject = (obj: {
251
data: any[];
252
options: Record<string, any>;
253
}) => {
254
return obj.data.map(item => ({ ...item, ...obj.options }));
255
};
256
257
const serializedMemoized = moize.serialize(processComplexObject);
258
259
const obj1 = { data: [{ id: 1 }], options: { active: true } };
260
const obj2 = { data: [{ id: 1 }], options: { active: true } }; // Different objects, same content
261
262
console.log(serializedMemoized(obj1)); // Computed
263
console.log(serializedMemoized(obj2)); // Cached (serialization matches)
264
265
// Custom serialization
266
const customSerializer = (key: any[]) => {
267
return key.map(arg => {
268
if (typeof arg === 'object' && arg !== null) {
269
// Sort object keys before stringifying for consistent serialization
270
const sortedObj = Object.keys(arg)
271
.sort()
272
.reduce((result, key) => {
273
result[key] = arg[key];
274
return result;
275
}, {} as any);
276
return JSON.stringify(sortedObj);
277
}
278
return String(arg);
279
});
280
};
281
282
const customSerializedMemoized = moize.serializeWith(customSerializer)(processComplexObject);
283
284
// Serialization with other options
285
const advancedSerialized = moize.serialize
286
.maxSize(20)
287
.maxAge(45000)
288
.profile('serialized-operations')(processComplexObject);
289
290
// Case-insensitive string serialization
291
const caseInsensitiveSerializer = (key: any[]) => {
292
return key.map(arg => {
293
if (typeof arg === 'string') {
294
return arg.toLowerCase();
295
}
296
return typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
297
});
298
};
299
300
const textProcessor = (text: string, options: { trim: boolean }) => {
301
return options.trim ? text.trim().toUpperCase() : text.toUpperCase();
302
};
303
304
const caseInsensitiveMemoized = moize.serializeWith(caseInsensitiveSerializer)(textProcessor);
305
306
console.log(caseInsensitiveMemoized("Hello", { trim: true })); // Computed
307
console.log(caseInsensitiveMemoized("HELLO", { trim: true })); // Cached (case-insensitive)
308
```
309
310
### Combining Specialized Methods
311
312
Specialized methods can be combined with other moize features for comprehensive optimization.
313
314
```typescript
315
import moize from "moize";
316
317
// Promise memoization with size and TTL limits
318
const apiCall = async (endpoint: string, params: Record<string, any>) => {
319
const url = new URL(endpoint);
320
Object.entries(params).forEach(([key, value]) => {
321
url.searchParams.append(key, String(value));
322
});
323
324
const response = await fetch(url.toString());
325
return response.json();
326
};
327
328
const optimizedApiCall = moize.promise
329
.serialize // Handle complex params objects
330
.maxSize(100) // Cache up to 100 different calls
331
.maxAge(300000) // 5 minute TTL
332
.profile('api') // Monitor performance
333
(apiCall);
334
335
// React component with deep comparison and size limit
336
const DataVisualization: React.FC<{
337
data: Array<{ id: string; values: number[] }>;
338
config: {
339
chartType: 'bar' | 'line' | 'pie';
340
colors: string[];
341
showLegend: boolean;
342
};
343
}> = ({ data, config }) => {
344
// Complex chart rendering
345
return <div>{/* chart content */}</div>;
346
};
347
348
const MemoizedVisualization = moize.react
349
.deep // Deep comparison for data and config
350
.maxSize(5) // Keep 5 different data/config combinations
351
(DataVisualization);
352
```
353
354
### Performance Considerations
355
356
Different specialized methods have different performance characteristics:
357
358
- **Promise memoization**: Best for async operations with network calls or heavy computations
359
- **React memoization**: Optimizes component re-rendering, especially with complex props
360
- **Serialization**: Adds overhead but enables complex object comparison without deep equality