0
# Selector Creation
1
2
Core functionality for creating memoized selectors using the default `createSelector` function and customizable options.
3
4
## Capabilities
5
6
### createSelector
7
8
Creates a memoized selector that computes derived data from state. The selector will only recompute when one of its input selectors returns a different value.
9
10
```typescript { .api }
11
/**
12
* Creates a memoized selector from input selectors and a result function
13
* @param selectors - Array of input selector functions
14
* @param combiner - Function that combines the results of input selectors
15
* @returns Memoized output selector with additional metadata
16
*/
17
function createSelector<State, Result>(
18
selectors: SelectorArray<State>,
19
combiner: (...args: any[]) => Result
20
): OutputSelector<State, Result>;
21
22
/**
23
* Creates a memoized selector with custom options
24
* @param selectors - Array of input selector functions
25
* @param combiner - Function that combines the results of input selectors
26
* @param options - Configuration options for memoization and dev mode checks
27
* @returns Memoized output selector with additional metadata
28
*/
29
function createSelector<State, Result>(
30
selectors: SelectorArray<State>,
31
combiner: (...args: any[]) => Result,
32
options: CreateSelectorOptions
33
): OutputSelector<State, Result>;
34
35
/**
36
* Variadic overload for inline input selectors
37
* @param selector1 - First input selector
38
* @param selector2 - Second input selector
39
* @param combiner - Function that combines selector results
40
* @returns Memoized output selector
41
*/
42
function createSelector<State, Res1, Res2, Result>(
43
selector1: Selector<State, Res1>,
44
selector2: Selector<State, Res2>,
45
combiner: (res1: Res1, res2: Res2) => Result
46
): OutputSelector<State, Result>;
47
48
// Additional overloads for 3-12 input selectors...
49
```
50
51
**Basic Usage:**
52
53
```typescript
54
import { createSelector } from "reselect";
55
56
// Simple selector with two inputs
57
const selectShopItems = (state) => state.shop.items;
58
const selectTaxPercent = (state) => state.shop.taxPercent;
59
60
const selectSubtotal = createSelector(
61
[selectShopItems],
62
(items) => items.reduce((acc, item) => acc + item.price, 0)
63
);
64
65
const selectTax = createSelector(
66
[selectSubtotal, selectTaxPercent],
67
(subtotal, taxPercent) => subtotal * (taxPercent / 100)
68
);
69
70
const selectTotal = createSelector(
71
[selectSubtotal, selectTax],
72
(subtotal, tax) => ({ total: subtotal + tax })
73
);
74
```
75
76
**With Custom Options:**
77
78
```typescript
79
import { createSelector, lruMemoize } from "reselect";
80
81
const selectExpensiveComputation = createSelector(
82
[selectLargeDataset],
83
(data) => computeExpensiveDerivation(data),
84
{
85
memoize: lruMemoize,
86
memoizeOptions: { maxSize: 10 },
87
devModeChecks: { inputStabilityCheck: 'always' }
88
}
89
);
90
```
91
92
### OutputSelector Interface
93
94
The enhanced selector returned by `createSelector` with additional metadata and methods.
95
96
```typescript { .api }
97
interface OutputSelector<State, Result, Params extends readonly any[] = any[]>
98
extends Selector<State, Result, Params> {
99
/** The original result function passed to createSelector */
100
resultFunc: (...args: any[]) => Result;
101
102
/** The memoization function used by this selector */
103
memoize: UnknownMemoizer;
104
105
/** The arguments memoization function used by this selector */
106
argsMemoize: UnknownMemoizer;
107
108
/** Array of input selectors used by this selector */
109
dependencies: SelectorArray<State>;
110
111
/** Returns the number of times the result function has been recomputed */
112
recomputations: () => number;
113
114
/** Resets the recomputation counter to 0 */
115
resetRecomputations: () => void;
116
117
/** Returns the number of times the dependencies have been recomputed */
118
dependencyRecomputations: () => number;
119
120
/** Resets the dependency recomputation counter to 0 */
121
resetDependencyRecomputations: () => void;
122
123
/** Returns the last computed result */
124
lastResult: () => Result;
125
126
/** The memoized version of the result function */
127
memoizedResultFunc: (...args: any[]) => Result;
128
}
129
```
130
131
**Usage Examples:**
132
133
```typescript
134
const mySelector = createSelector([selectA, selectB], (a, b) => a + b);
135
136
// Check recomputation counts
137
console.log(mySelector.recomputations()); // 0
138
console.log(mySelector.dependencyRecomputations()); // 0
139
140
// Use the selector
141
const result1 = mySelector(state);
142
console.log(mySelector.recomputations()); // 1
143
console.log(mySelector.dependencyRecomputations()); // 1
144
145
// Same inputs won't recompute
146
const result2 = mySelector(state);
147
console.log(mySelector.recomputations()); // Still 1
148
console.log(mySelector.dependencyRecomputations()); // Still 1
149
150
// Get the last result
151
console.log(mySelector.lastResult()); // The computed result
152
153
// Reset counters
154
mySelector.resetRecomputations();
155
mySelector.resetDependencyRecomputations();
156
console.log(mySelector.recomputations()); // 0
157
console.log(mySelector.dependencyRecomputations()); // 0
158
159
// Access the underlying result function
160
const directResult = mySelector.resultFunc(valueA, valueB);
161
```
162
163
### CreateSelectorOptions
164
165
Configuration options for customizing selector behavior.
166
167
```typescript { .api }
168
interface CreateSelectorOptions<MemoizeFunction = typeof weakMapMemoize> {
169
/** Custom memoization function (defaults to weakMapMemoize) */
170
memoize?: MemoizeFunction;
171
172
/** Options passed to the memoization function */
173
memoizeOptions?: ExtractMemoizerFields<MemoizeFunction>;
174
175
/** Custom arguments memoization function (defaults to weakMapMemoize) */
176
argsMemoize?: UnknownMemoizer;
177
178
/** Options passed to the arguments memoization function */
179
argsMemoizeOptions?: unknown[];
180
181
/** Development mode check configuration */
182
devModeChecks?: Partial<DevModeChecks>;
183
}
184
185
interface DevModeChecks {
186
/** Check for unstable input selector results */
187
inputStabilityCheck: DevModeCheckFrequency;
188
189
/** Check if result function is an identity function */
190
identityFunctionCheck: DevModeCheckFrequency;
191
}
192
193
type DevModeCheckFrequency = 'once' | 'always' | 'never';
194
```
195
196
### Parametric Selectors
197
198
Selectors that accept additional parameters beyond state.
199
200
```typescript
201
import { createSelector } from "reselect";
202
203
// Selector with parameters
204
const selectTodoById = createSelector(
205
[(state, id) => state.todos, (state, id) => id],
206
(todos, id) => todos.find(todo => todo.id === id)
207
);
208
209
// Usage with parameters
210
const todo = selectTodoById(state, 42);
211
212
// Factory pattern for parametric selectors
213
const makeSelectorTodosByStatus = () => createSelector(
214
[(state, status) => state.todos, (state, status) => status],
215
(todos, status) => todos.filter(todo => todo.status === status)
216
);
217
218
const selectCompletedTodos = makeSelectorTodosByStatus();
219
const completedTodos = selectCompletedTodos(state, 'completed');
220
```
221
222
### Pre-Typed Selectors
223
224
Create pre-typed versions of `createSelector` with predefined state types to eliminate repetitive type annotations.
225
226
```typescript
227
import { createSelector } from "reselect";
228
229
interface RootState {
230
todos: { id: number; completed: boolean }[];
231
alerts: { id: number; read: boolean }[];
232
}
233
234
// Create a pre-typed createSelector with RootState
235
export const createAppSelector = createSelector.withTypes<RootState>();
236
237
// Now you can use createAppSelector without specifying state types
238
const selectTodoIds = createAppSelector(
239
[
240
// Type of `state` is automatically set to `RootState`
241
state => state.todos
242
],
243
todos => todos.map(({ id }) => id)
244
);
245
246
const selectActiveAlerts = createAppSelector(
247
[state => state.alerts],
248
alerts => alerts.filter(alert => !alert.read)
249
);
250
```
251
252
## Types
253
254
```typescript { .api }
255
type Selector<State = any, Result = unknown, Params extends readonly any[] = any[]> =
256
(state: State, ...params: Params) => Result;
257
258
type SelectorArray<State = any> = readonly Selector<State>[];
259
260
type SelectorResultArray<Selectors extends SelectorArray> = {
261
[Index in keyof Selectors]: Selectors[Index] extends Selector<any, infer Result>
262
? Result
263
: never;
264
};
265
266
type Combiner<Result> = (...args: any[]) => Result;
267
268
type UnknownMemoizer = (func: AnyFunction, ...options: unknown[]) => AnyFunction;
269
270
type AnyFunction = (...args: any[]) => any;
271
```