0
# Development Mode Utilities
1
2
Development-only stability checks and debugging utilities to help identify common selector issues and ensure optimal performance.
3
4
## Capabilities
5
6
### setGlobalDevModeChecks
7
8
Configures global development mode check settings for all selectors in the application.
9
10
```typescript { .api }
11
/**
12
* Overrides the development mode checks settings for all selectors
13
* @param devModeChecks - Partial configuration object for dev mode checks
14
*/
15
function setGlobalDevModeChecks(devModeChecks: Partial<DevModeChecks>): void;
16
17
interface DevModeChecks {
18
/** Check for unstable input selector results */
19
inputStabilityCheck: DevModeCheckFrequency;
20
21
/** Check if result function is an identity function */
22
identityFunctionCheck: DevModeCheckFrequency;
23
}
24
25
type DevModeCheckFrequency = 'once' | 'always' | 'never';
26
```
27
28
**Basic Usage:**
29
30
```typescript
31
import { setGlobalDevModeChecks } from "reselect";
32
33
// Run checks only on first selector call (default)
34
setGlobalDevModeChecks({
35
inputStabilityCheck: 'once',
36
identityFunctionCheck: 'once'
37
});
38
39
// Run checks on every selector call
40
setGlobalDevModeChecks({
41
inputStabilityCheck: 'always',
42
identityFunctionCheck: 'always'
43
});
44
45
// Disable specific checks
46
setGlobalDevModeChecks({
47
inputStabilityCheck: 'never',
48
identityFunctionCheck: 'once'
49
});
50
51
// Partial configuration (unspecified settings retain current values)
52
setGlobalDevModeChecks({
53
inputStabilityCheck: 'always'
54
// identityFunctionCheck keeps its current setting
55
});
56
```
57
58
### Development Mode Checks Overview
59
60
Development mode checks help identify common selector performance issues and mistakes.
61
62
**Input Stability Check:**
63
- Detects when input selectors return different references for the same inputs
64
- Helps identify unnecessary recomputations due to unstable input selectors
65
- Warns when input selectors create new objects/arrays on each call
66
67
**Identity Function Check:**
68
- Detects when the result function just returns its first argument unchanged
69
- Helps identify selectors that don't add value and could be simplified
70
- Warns about potential performance issues with unnecessary selector layers
71
72
### Per-Selector Configuration
73
74
Override global settings for specific selectors using `CreateSelectorOptions`.
75
76
```typescript
77
import { createSelector } from "reselect";
78
79
// Override global settings for specific selector
80
const selectSpecialData = createSelector(
81
[selectInputData],
82
(data) => processData(data),
83
{
84
devModeChecks: {
85
inputStabilityCheck: 'always', // Always check this selector
86
identityFunctionCheck: 'never' // Never check identity for this one
87
}
88
}
89
);
90
91
// Disable all checks for performance-critical selector
92
const selectCriticalPath = createSelector(
93
[selectLargeDataset],
94
(data) => criticalProcessing(data),
95
{
96
devModeChecks: {
97
inputStabilityCheck: 'never',
98
identityFunctionCheck: 'never'
99
}
100
}
101
);
102
```
103
104
### Common Issues and Solutions
105
106
**Unstable Input Selectors:**
107
108
```typescript
109
import { createSelector } from "reselect";
110
111
// ❌ BAD: Creates new array on every call
112
const selectBadItems = (state) => state.items.filter(item => item.active);
113
114
// ✅ GOOD: Stable input selector
115
const selectItems = (state) => state.items;
116
const selectActiveFilter = (state) => true; // or from actual filter state
117
118
const selectActiveItems = createSelector(
119
[selectItems, selectActiveFilter],
120
(items, shouldFilterActive) =>
121
shouldFilterActive ? items.filter(item => item.active) : items
122
);
123
```
124
125
**Identity Function Issues:**
126
127
```typescript
128
import { createSelector } from "reselect";
129
130
// ❌ BAD: Identity function - just returns first argument
131
const selectBadUser = createSelector(
132
[(state) => state.user],
133
(user) => user // This is an identity function
134
);
135
136
// ✅ GOOD: Actually transforms the data
137
const selectUserDisplayName = createSelector(
138
[(state) => state.user],
139
(user) => user ? `${user.firstName} ${user.lastName}` : 'Anonymous'
140
);
141
142
// ✅ ALSO GOOD: Direct selector when no transformation needed
143
const selectUser = (state) => state.user;
144
```
145
146
### DevModeChecksExecutionInfo
147
148
Information about development mode check execution (internal type).
149
150
```typescript { .api }
151
interface DevModeChecksExecutionInfo {
152
/** Information about input stability check execution */
153
inputStabilityCheck: DevModeCheckExecutionInfo;
154
155
/** Information about identity function check execution */
156
identityFunctionCheck: DevModeCheckExecutionInfo;
157
}
158
159
interface DevModeCheckExecutionInfo {
160
/** Whether the check should run */
161
shouldRun: boolean;
162
163
/** Number of times this check has been executed */
164
timesRun: number;
165
}
166
```
167
168
### Production Behavior
169
170
Development mode checks are automatically disabled in production builds to ensure optimal performance.
171
172
```typescript
173
// Development mode checks only run when process.env.NODE_ENV !== 'production'
174
// In production, these checks are completely bypassed for performance
175
176
import { createSelector, setGlobalDevModeChecks } from "reselect";
177
178
// This configuration only affects development builds
179
setGlobalDevModeChecks({ inputStabilityCheck: 'always' });
180
181
const selectData = createSelector(
182
[selectInput],
183
(input) => processInput(input)
184
// Dev mode checks run in development, ignored in production
185
);
186
```
187
188
### Debugging and Monitoring
189
190
**Checking Recomputations:**
191
192
```typescript
193
import { createSelector } from "reselect";
194
195
const selectExpensiveData = createSelector(
196
[selectLargeDataset, selectFilters],
197
(data, filters) => expensiveProcessing(data, filters)
198
);
199
200
// Monitor recomputations in development
201
console.log('Recomputations:', selectExpensiveData.recomputations());
202
203
// Use the selector
204
const result = selectExpensiveData(state);
205
console.log('After use:', selectExpensiveData.recomputations());
206
207
// Reset counter for testing
208
selectExpensiveData.resetRecomputations();
209
```
210
211
**Custom Development Logging:**
212
213
```typescript
214
import { createSelector } from "reselect";
215
216
const selectWithLogging = createSelector(
217
[selectInput],
218
(input) => {
219
if (process.env.NODE_ENV === 'development') {
220
console.log('Selector recomputing with input:', input);
221
}
222
return processInput(input);
223
}
224
);
225
```
226
227
### Integration with Testing
228
229
```typescript
230
import { createSelector, setGlobalDevModeChecks } from "reselect";
231
232
describe('Selector Tests', () => {
233
beforeEach(() => {
234
// Enable all checks for testing
235
setGlobalDevModeChecks({
236
inputStabilityCheck: 'always',
237
identityFunctionCheck: 'always'
238
});
239
});
240
241
it('should not recompute with same inputs', () => {
242
const selector = createSelector(
243
[(state) => state.data],
244
(data) => processData(data)
245
);
246
247
selector(state1);
248
const recomputations1 = selector.recomputations();
249
250
selector(state1); // Same state
251
const recomputations2 = selector.recomputations();
252
253
expect(recomputations2).toBe(recomputations1); // Should not increase
254
});
255
});
256
```
257
258
## Types
259
260
```typescript { .api }
261
interface DevModeChecks {
262
inputStabilityCheck: DevModeCheckFrequency;
263
identityFunctionCheck: DevModeCheckFrequency;
264
}
265
266
type DevModeCheckFrequency = 'once' | 'always' | 'never';
267
268
interface DevModeChecksExecutionInfo {
269
inputStabilityCheck: DevModeCheckExecutionInfo;
270
identityFunctionCheck: DevModeCheckExecutionInfo;
271
}
272
273
interface DevModeCheckExecutionInfo {
274
shouldRun: boolean;
275
timesRun: number;
276
}
277
```