react-state-basis 0.3.4 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +212 -123
- package/dist/index.js +166 -139
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +166 -139
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,13 +5,15 @@
|
|
|
5
5
|
<div align="center">
|
|
6
6
|
|
|
7
7
|
# 📐 react-state-basis
|
|
8
|
-
### Runtime
|
|
8
|
+
### Runtime Architectural Auditor & State Profiler for React
|
|
9
9
|
|
|
10
10
|
[](https://www.npmjs.com/package/react-state-basis)
|
|
11
11
|
[](https://github.com/liovic/react-state-basis/stargazers)
|
|
12
12
|
[](https://opensource.org/licenses/MIT)
|
|
13
13
|
|
|
14
|
-
**
|
|
14
|
+
**Basis tracks the rhythm of state updates, not the data. It identifies redundant patterns and sync-leaks that standard tools miss.**
|
|
15
|
+
|
|
16
|
+
> Stop relying on architectural intuition. Start measuring architectural debt.
|
|
15
17
|
|
|
16
18
|
</div>
|
|
17
19
|
|
|
@@ -26,7 +28,7 @@
|
|
|
26
28
|
- **Infinite loops** - Circular dependencies that freeze your browser
|
|
27
29
|
- **Tight coupling** - State variables that should be independent but aren't
|
|
28
30
|
|
|
29
|
-
It works by tracking *when* state updates happen, not *what* the values are.
|
|
31
|
+
It works by tracking *when* state updates happen (temporal patterns), not *what* the values are.
|
|
30
32
|
|
|
31
33
|
---
|
|
32
34
|
|
|
@@ -37,7 +39,7 @@ const [user, setUser] = useState(null);
|
|
|
37
39
|
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
|
38
40
|
|
|
39
41
|
useEffect(() => {
|
|
40
|
-
setIsLoggedIn(!!user); // Double render - flagged as
|
|
42
|
+
setIsLoggedIn(!!user); // Double render - flagged as sync leak
|
|
41
43
|
}, [user]);
|
|
42
44
|
|
|
43
45
|
// ✅ Better
|
|
@@ -49,14 +51,40 @@ const isLoggedIn = !!user; // Computed, no second render
|
|
|
49
51
|
|
|
50
52
|
## See It Work
|
|
51
53
|
|
|
52
|
-
The optional HUD shows
|
|
54
|
+
The optional HUD shows your state basis matrix in real-time:
|
|
53
55
|
|
|
54
56
|
<p align="center">
|
|
55
|
-
<img src="./assets/react-state-basis.gif" width="800" alt="React State Basis Demo" />
|
|
57
|
+
<img src="./assets/react-state-basis-demo.gif" width="800" alt="React State Basis Demo" />
|
|
56
58
|
</p>
|
|
57
59
|
|
|
58
60
|
---
|
|
59
61
|
|
|
62
|
+
## Real-World Audits
|
|
63
|
+
|
|
64
|
+
Basis has been tested on major open-source projects to validate detection accuracy:
|
|
65
|
+
|
|
66
|
+
### Excalidraw (114k+ ⭐)
|
|
67
|
+
**Detected:** Causal Sync Leak in theme state synchronization
|
|
68
|
+
**Issue:** A `useEffect` was manually syncing theme state, causing an unnecessary double render on every theme toggle
|
|
69
|
+
**Fix:** [PR #10637](https://github.com/excalidraw/excalidraw/pull/10637) - Replaced with a computed value
|
|
70
|
+
|
|
71
|
+
<p align="center">
|
|
72
|
+
<img src="./assets/excalidraw-audit.png" width="800" alt="Excalidraw Audit" />
|
|
73
|
+
</p>
|
|
74
|
+
|
|
75
|
+
### shadcn-admin (10k+ ⭐)
|
|
76
|
+
**Detected:** Redundant state pattern in mobile detection hooks
|
|
77
|
+
**Issue:** Viewport resize events were being synchronized via effects rather than direct subscriptions
|
|
78
|
+
**Fix:** [PR #274](https://github.com/satnaing/shadcn-admin/pull/274) - Optimized subscription pattern
|
|
79
|
+
|
|
80
|
+
<p align="center">
|
|
81
|
+
<img src="./assets/shadcn-admin.png" width="800" alt="shadcn Admin Audit" />
|
|
82
|
+
</p>
|
|
83
|
+
|
|
84
|
+
> **Note:** These are proposed architectural improvements. Basis points out patterns worth investigating - the final decision rests with the maintainer.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
60
88
|
## Setup (Vite)
|
|
61
89
|
|
|
62
90
|
### 1. Install
|
|
@@ -91,7 +119,19 @@ root.render(
|
|
|
91
119
|
);
|
|
92
120
|
```
|
|
93
121
|
|
|
94
|
-
|
|
122
|
+
### 4. Verify It's Working
|
|
123
|
+
|
|
124
|
+
Add this test pattern to any component:
|
|
125
|
+
```tsx
|
|
126
|
+
const [a, setA] = useState(0);
|
|
127
|
+
const [b, setB] = useState(0);
|
|
128
|
+
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
setB(a); // Basis will flag this
|
|
131
|
+
}, [a]);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Trigger an update (e.g., click a button that calls `setA(1)`). You should see a console alert within ~100ms.
|
|
95
135
|
|
|
96
136
|
---
|
|
97
137
|
|
|
@@ -99,213 +139,262 @@ That's it. The tool runs automatically in development.
|
|
|
99
139
|
|
|
100
140
|
### Console Alerts
|
|
101
141
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
**Redundant State:**
|
|
142
|
+
**Redundant Pattern:**
|
|
143
|
+
Detected when two variables move in perfect unison.
|
|
105
144
|
```
|
|
106
|
-
📐 BASIS | REDUNDANT
|
|
145
|
+
📐 BASIS | REDUNDANT PATTERN
|
|
107
146
|
📍 Location: TodoList.tsx
|
|
108
|
-
|
|
109
|
-
One is likely
|
|
110
|
-
|
|
111
|
-
Suggested fix: Convert "count" to a computed value
|
|
147
|
+
Observation: "todos" and "count" move together.
|
|
148
|
+
One is likely a direct mirror of the other. Confidence: 94%
|
|
149
|
+
Action: Refactor "count" to useMemo.
|
|
112
150
|
```
|
|
113
151
|
|
|
114
|
-
**
|
|
152
|
+
**Sync Leak (Causal Chain):**
|
|
153
|
+
Detected when one variable consistently triggers another with a temporal lag.
|
|
115
154
|
```
|
|
116
|
-
💡 BASIS |
|
|
117
|
-
|
|
118
|
-
|
|
155
|
+
💡 BASIS | DETECTED SYNC LEAK
|
|
156
|
+
📍 Location: AuthProvider.tsx
|
|
157
|
+
Flow: user ➔ Effect ➔ isLoggedIn
|
|
158
|
+
Context: The engine detected a consistent 20ms lag between these updates.
|
|
159
|
+
Result: This creates a Double Render Cycle.
|
|
119
160
|
```
|
|
120
161
|
|
|
121
|
-
**Infinite
|
|
162
|
+
**Infinite Loop:**
|
|
163
|
+
Detected when a variable updates too rapidly (circuit breaker).
|
|
122
164
|
```
|
|
123
|
-
🛑 BASIS |
|
|
124
|
-
|
|
125
|
-
Execution halted to prevent browser
|
|
165
|
+
🛑 BASIS CRITICAL | CIRCUIT BREAKER
|
|
166
|
+
Infinite oscillation detected on: "counter"
|
|
167
|
+
Execution halted to prevent browser thread lock.
|
|
126
168
|
```
|
|
127
169
|
|
|
128
170
|
### Health Report
|
|
129
171
|
|
|
130
|
-
Check your entire app's state
|
|
172
|
+
Check your entire app's state architecture:
|
|
131
173
|
```tsx
|
|
132
174
|
window.printBasisReport();
|
|
133
175
|
```
|
|
134
176
|
|
|
135
177
|
Shows:
|
|
136
|
-
-
|
|
137
|
-
-
|
|
138
|
-
- Correlation
|
|
178
|
+
- **Health Score** - Percentage of independent vs. synchronized state
|
|
179
|
+
- **Synchronized Clusters** - Groups of variables that move together
|
|
180
|
+
- **Correlation Matrix** - Full pairwise similarity analysis (for <15 variables)
|
|
139
181
|
|
|
140
182
|
---
|
|
141
183
|
|
|
142
|
-
##
|
|
143
|
-
|
|
144
|
-
I've tested this on a few open-source projects to validate the detection:
|
|
145
|
-
|
|
146
|
-
### Excalidraw (114k+ ⭐)
|
|
147
|
-
|
|
148
|
-
**Found:** Theme state being manually synchronized in `useEffect`
|
|
149
|
-
**Issue:** Double render on every theme change
|
|
150
|
-
**Fix:** [PR #10637](https://github.com/excalidraw/excalidraw/pull/10637) - replaced with computed value
|
|
151
|
-
**Status:** Pending review
|
|
152
|
-
|
|
153
|
-
<p align="center">
|
|
154
|
-
<img src="./assets/excalidraw-audit.png" width="800" alt="Excalidraw Audit" />
|
|
155
|
-
</p>
|
|
184
|
+
## How It Works (v0.4.0)
|
|
156
185
|
|
|
157
|
-
###
|
|
186
|
+
### Temporal Cross-Correlation
|
|
158
187
|
|
|
159
|
-
**
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
<img src="./assets/shadcn-admin.png" width="800" alt="shadcn Admin Audit" />
|
|
166
|
-
</p>
|
|
167
|
-
|
|
168
|
-
> **Note:** These are proposed improvements based on the tool's detection. The maintainers may choose different solutions or determine the patterns are intentional.
|
|
188
|
+
Basis tracks **when** state updates occur, creating a 50-tick timeline for each variable:
|
|
189
|
+
```
|
|
190
|
+
useState("count"): [0,0,1,0,0,1,1,0,...] (updates at ticks 2, 5, 6)
|
|
191
|
+
useState("total"): [0,0,1,0,0,1,1,0,...] (same pattern)
|
|
192
|
+
↑ Redundant: identical temporal signature
|
|
193
|
+
```
|
|
169
194
|
|
|
170
|
-
|
|
195
|
+
For every pair of variables, Basis checks three temporal relationships:
|
|
171
196
|
|
|
172
|
-
|
|
197
|
+
1. **Synchronous (Redundancy):** Do they update in the same tick?
|
|
198
|
+
```
|
|
199
|
+
A: [0,1,0,1,0,...]
|
|
200
|
+
B: [0,1,0,1,0,...] → Flagged as redundant
|
|
201
|
+
```
|
|
173
202
|
|
|
174
|
-
|
|
203
|
+
2. **Lead-Lag (A → B):** Does B consistently follow A in the next tick?
|
|
204
|
+
```
|
|
205
|
+
A: [0,1,0,1,0,...]
|
|
206
|
+
B: [0,0,1,0,1,...] → B follows A (sync leak detected)
|
|
207
|
+
```
|
|
175
208
|
|
|
176
|
-
|
|
209
|
+
3. **Lead-Lag (B → A):** Does A consistently follow B?
|
|
177
210
|
```
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
↑ Both update at same times = probably redundant
|
|
211
|
+
A: [0,0,1,0,1,...]
|
|
212
|
+
B: [0,1,0,1,0,...] → A follows B (reverse causality)
|
|
181
213
|
```
|
|
182
214
|
|
|
183
|
-
|
|
215
|
+
The engine uses **offset-based comparison** to check these patterns without allocating temporary arrays, ensuring minimal overhead even at high frame rates.
|
|
216
|
+
|
|
217
|
+
### Performance Optimizations
|
|
184
218
|
|
|
185
|
-
|
|
219
|
+
- **Idle Filtering:** Only analyzes variables with 2+ updates, reducing pairwise comparisons by ~90% in typical applications (measured on Excalidraw's 47-hook codebase)
|
|
220
|
+
- **Batched Analysis:** Runs every 5 ticks (~100ms) to avoid impacting frame budget
|
|
221
|
+
- **Console Throttling:** Same alert won't repeat within 5 seconds
|
|
222
|
+
- **Zero Production Overhead:** Entire library is replaced with no-op shims in production builds
|
|
186
223
|
|
|
187
|
-
###
|
|
224
|
+
### What Gets Flagged?
|
|
188
225
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
226
|
+
**Redundant Pattern Example:**
|
|
227
|
+
```tsx
|
|
228
|
+
// ❌ Before (Basis flags this)
|
|
229
|
+
const [count, setCount] = useState(0);
|
|
230
|
+
const [doubled, setDoubled] = useState(0);
|
|
193
231
|
|
|
194
|
-
|
|
232
|
+
useEffect(() => {
|
|
233
|
+
setDoubled(count * 2);
|
|
234
|
+
}, [count]);
|
|
195
235
|
|
|
196
|
-
|
|
236
|
+
// ✅ After (Basis suggestion)
|
|
237
|
+
const [count, setCount] = useState(0);
|
|
238
|
+
const doubled = useMemo(() => count * 2, [count]);
|
|
239
|
+
```
|
|
197
240
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
❌
|
|
201
|
-
|
|
241
|
+
**Sync Leak Example:**
|
|
242
|
+
```tsx
|
|
243
|
+
// ❌ Before (causes double render)
|
|
244
|
+
const [user, setUser] = useState(null);
|
|
245
|
+
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
|
202
246
|
|
|
203
|
-
|
|
247
|
+
useEffect(() => {
|
|
248
|
+
setIsLoggedIn(!!user);
|
|
249
|
+
}, [user]);
|
|
250
|
+
|
|
251
|
+
// ✅ After (single render)
|
|
252
|
+
const [user, setUser] = useState(null);
|
|
253
|
+
const isLoggedIn = !!user; // Derived, no effect needed
|
|
254
|
+
```
|
|
204
255
|
|
|
205
256
|
---
|
|
206
257
|
|
|
207
258
|
## Production Safety
|
|
208
259
|
|
|
209
|
-
In production builds, the entire tool is
|
|
260
|
+
In production builds, the entire tool is replaced with zero-op shims. **Zero runtime overhead. Zero bundle size increase.**
|
|
210
261
|
```json
|
|
211
262
|
// package.json - automatic based on NODE_ENV
|
|
212
263
|
"exports": {
|
|
213
264
|
".": {
|
|
214
265
|
"development": "./dist/index.mjs",
|
|
215
|
-
"production": "./dist/production.mjs", //
|
|
266
|
+
"production": "./dist/production.mjs", // No-op shims
|
|
216
267
|
"default": "./dist/production.mjs"
|
|
217
268
|
}
|
|
218
269
|
}
|
|
219
270
|
```
|
|
220
271
|
|
|
221
|
-
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## When to Skip Files
|
|
275
|
+
|
|
276
|
+
Add `// @basis-ignore` at the top of a file to disable instrumentation:
|
|
277
|
+
```tsx
|
|
278
|
+
// @basis-ignore
|
|
279
|
+
// This file uses third-party library wrappers or hardware-bound synchronization that Basis shouldn't audit.
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Good candidates for skipping:**
|
|
283
|
+
- **High-frequency animations** (>60fps state updates)
|
|
284
|
+
- **WebSocket message handlers** (rapid, intentional updates)
|
|
285
|
+
- **Canvas/WebGL render loops** (performance-critical paths)
|
|
286
|
+
- **Intentional synchronization** (e.g., React Query → local cache mirrors)
|
|
287
|
+
- **Third-party library wrappers** (where you don't control the architecture)
|
|
222
288
|
|
|
223
289
|
---
|
|
224
290
|
|
|
225
291
|
## Comparison to Other Tools
|
|
226
292
|
|
|
227
|
-
| Tool |
|
|
228
|
-
|
|
229
|
-
| **React DevTools** | Component
|
|
230
|
-
| **Why Did You Render** |
|
|
231
|
-
| **ESLint exhaustive-deps** |
|
|
232
|
-
| **react-state-basis** |
|
|
293
|
+
| Tool | Focus | When to Use |
|
|
294
|
+
|------|-------|-------------|
|
|
295
|
+
| **React DevTools** | Component hierarchy & values | Debugging specific components |
|
|
296
|
+
| **Why Did You Render** | Re-render optimization | Performance tuning renders |
|
|
297
|
+
| **ESLint exhaustive-deps** | Static dependency analysis | Preventing missing deps |
|
|
298
|
+
| **react-state-basis** | **Temporal state relationships** | **Finding redundant state & effect chains** |
|
|
233
299
|
|
|
234
|
-
|
|
300
|
+
These tools are complementary - use them together for best results.
|
|
235
301
|
|
|
236
302
|
---
|
|
237
303
|
|
|
238
|
-
##
|
|
304
|
+
## Performance Impact (Measured)
|
|
239
305
|
|
|
240
|
-
|
|
241
|
-
```tsx
|
|
242
|
-
// @basis-ignore
|
|
243
|
-
```
|
|
306
|
+
**Development Mode**
|
|
244
307
|
|
|
245
|
-
|
|
246
|
-
- Animation loops
|
|
247
|
-
- High-frequency timers
|
|
248
|
-
- WebSocket handlers
|
|
249
|
-
- Performance-critical code
|
|
308
|
+
These measurements were taken using the built-in **Stress Lab** with 100 active hooks and continuous state updates, observed in Chrome DevTools Performance and Web Vitals panels.
|
|
250
309
|
|
|
251
|
-
|
|
310
|
+
Location: `/example`
|
|
252
311
|
|
|
253
|
-
|
|
312
|
+
**Observed impact:**
|
|
254
313
|
|
|
255
|
-
|
|
314
|
+
* **Per update overhead:** < 0.05ms (O(1) Map-based tracking)
|
|
315
|
+
* **Analysis pass:** ~1.0ms (Zero-copy pointer math)
|
|
316
|
+
* **Frame budget impact:** ~2% during active 100-hook stress testing
|
|
317
|
+
* **Latency (INP):** 80ms (v0.4.0) vs 464ms (v0.3.x legacy engine)
|
|
256
318
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
-
|
|
261
|
-
|
|
319
|
+
> Results will vary by hardware, browser, and workload. Use the Stress Lab to reproduce and compare Basis ON vs OFF in your own environment.
|
|
320
|
+
|
|
321
|
+
<p align="center">
|
|
322
|
+
<img src="./assets/react-state-basis-stress.gif" width="800" alt="shadcn Admin Audit" />
|
|
323
|
+
</p>
|
|
262
324
|
|
|
263
|
-
**Known issues:**
|
|
264
|
-
- ⚠️ May miss delayed chains (>20ms apart)
|
|
265
|
-
- ⚠️ Can flag intentional patterns as issues
|
|
266
|
-
- ⚠️ Complex multi-way dependencies might not be caught
|
|
267
|
-
- ⚠️ Requires judgment to interpret results
|
|
268
325
|
|
|
269
|
-
**
|
|
326
|
+
**Production Mode:**
|
|
327
|
+
- Overhead: ~0.01ms per hook call (negligible wrapper overhead)
|
|
328
|
+
- Bundle size: ~2-3 KB minified (no-op wrappers only, no analysis engine)
|
|
329
|
+
- Monitoring logic: 100% removed
|
|
330
|
+
- HUD component: 100% removed
|
|
270
331
|
|
|
271
332
|
---
|
|
272
333
|
|
|
273
|
-
##
|
|
334
|
+
## Limitations (v0.4.x)
|
|
274
335
|
|
|
275
|
-
|
|
276
|
-
-
|
|
277
|
-
-
|
|
278
|
-
-
|
|
279
|
-
-
|
|
336
|
+
**What works well:**
|
|
337
|
+
- ✅ Detecting synchronous redundant state
|
|
338
|
+
- ✅ Flagging effect-driven update chains (A → Effect → B)
|
|
339
|
+
- ✅ Catching infinite loops before browser freeze
|
|
340
|
+
- ✅ Distinguishing causality from redundancy
|
|
341
|
+
|
|
342
|
+
**Known edge cases:**
|
|
343
|
+
- ⚠️ **Async gaps:** Updates delayed by >40ms (e.g., slow API responses) may appear independent
|
|
344
|
+
- ⚠️ **Intentional sync:** Sometimes synchronization is required for library compatibility
|
|
345
|
+
- ⚠️ **Complex multi-way dependencies:** Three or more interconnected states might not show full relationship graph
|
|
346
|
+
- ⚠️ **Requires judgment:** Tool points out patterns worth investigating - you decide if they're issues
|
|
280
347
|
|
|
281
|
-
|
|
282
|
-
- [ ] Visual state dependency graph
|
|
283
|
-
- [ ] Domain isolation analysis
|
|
284
|
-
- [ ] Historical trend tracking
|
|
348
|
+
**Heuristic interpretation requires context. Always verify architectural intent before refactoring.**.
|
|
285
349
|
|
|
286
350
|
---
|
|
287
351
|
|
|
288
|
-
##
|
|
352
|
+
## Roadmap
|
|
289
353
|
|
|
290
|
-
|
|
354
|
+
### v0.4.x
|
|
355
|
+
- [x] **v0.4.0**: Temporal Cross-Correlation Engine (Lead-Lag Analysis)
|
|
356
|
+
- [x] **v0.4.1:** Density Filtering (Eliminate false positives from animations/sliders)
|
|
357
|
+
- [ ] v0.4.2: Ring Buffer (Zero-jank memory management for 500+ hooks)
|
|
291
358
|
|
|
292
|
-
|
|
359
|
+
### v0.5.0 (Planned)
|
|
360
|
+
- [ ] Zustand & Redux middleware integration
|
|
361
|
+
- [ ] Visual dependency graph in HUD
|
|
362
|
+
- [ ] Historical trend tracking across sessions
|
|
363
|
+
|
|
364
|
+
### Future Ideas
|
|
365
|
+
- [ ] Domain isolation analysis (detect feature boundaries)
|
|
366
|
+
- [ ] Export audit reports for team reviews
|
|
367
|
+
- [ ] CI integration for architectural regressions
|
|
293
368
|
|
|
294
369
|
---
|
|
295
370
|
|
|
296
371
|
## FAQ
|
|
297
372
|
|
|
298
373
|
**Q: Will this slow down my app?**
|
|
299
|
-
A: Only in development. Production builds
|
|
374
|
+
A: Only in development (~0.3ms per update). Production builds have zero overhead.
|
|
300
375
|
|
|
301
376
|
**Q: Do I have to change my code?**
|
|
302
377
|
A: No. The Babel plugin instruments hooks automatically.
|
|
303
378
|
|
|
304
379
|
**Q: What if it flags something that's not a problem?**
|
|
305
|
-
A: Use your judgment.
|
|
380
|
+
A: Use your judgment. Basis is a diagnostic tool that points out patterns worth investigating - not all flagged patterns are bugs.
|
|
381
|
+
|
|
382
|
+
**Q: How is this different from Redux DevTools?**
|
|
383
|
+
A: Redux DevTools shows state values and action history. Basis shows temporal relationships between state variables, regardless of what state management library you use.
|
|
306
384
|
|
|
307
385
|
**Q: Why "basis"?**
|
|
308
|
-
A: In linear algebra, a "basis" is a minimal set of independent vectors. The name reflects the goal of finding your app's minimal independent state.
|
|
386
|
+
A: In linear algebra, a "basis" is a minimal set of independent vectors. The name reflects the goal of finding your app's minimal independent state - removing redundancy.
|
|
387
|
+
|
|
388
|
+
**Q: How is this different from Redux DevTools?**
|
|
389
|
+
A: Redux DevTools is a **Journal** - it logs specific values and actions within a Redux store. Basis is an **Architectural Auditor** - it instruments React's core primitives (useState, useReducer, useEffect) to detect hidden relationships between entirely separate components and hooks, even when they don't share a store. Redux DevTools answers "what changed and why?" while Basis answers "is this state architecture clean?"
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## Contributing
|
|
394
|
+
|
|
395
|
+
Found a bug? Have an idea? Open an issue or PR.
|
|
396
|
+
|
|
397
|
+
For technical details on how the detection works, see the [Wiki](https://github.com/liovic/react-state-basis/wiki).
|
|
309
398
|
|
|
310
399
|
---
|
|
311
400
|
|