You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- 5.1 [Defer State Reads to Usage Point](#51-defer-state-reads-to-usage-point)
50
-
- 5.2 [Do not wrap a simple expression with a primitive result type in useMemo](#52-do-not-wrap-a-simple-expression-with-a-primitive-result-type-in-usememo)
51
-
- 5.3 [Extract Default Non-primitive Parameter Value from Memoized Component to Constant](#53-extract-default-non-primitive-parameter-value-from-memoized-component-to-constant)
52
-
- 5.4 [Extract to Memoized Components](#54-extract-to-memoized-components)
- 5.8 [Use Lazy State Initialization](#58-use-lazy-state-initialization)
57
-
- 5.9 [Use Transitions for Non-Urgent Updates](#59-use-transitions-for-non-urgent-updates)
49
+
- 5.1 [Calculate Derived State During Rendering](#51-calculate-derived-state-during-rendering)
50
+
- 5.2 [Defer State Reads to Usage Point](#52-defer-state-reads-to-usage-point)
51
+
- 5.3 [Do not wrap a simple expression with a primitive result type in useMemo](#53-do-not-wrap-a-simple-expression-with-a-primitive-result-type-in-usememo)
52
+
- 5.4 [Extract Default Non-primitive Parameter Value from Memoized Component to Constant](#54-extract-default-non-primitive-parameter-value-from-memoized-component-to-constant)
53
+
- 5.5 [Extract to Memoized Components](#55-extract-to-memoized-components)
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, manual memoization with `memo()` and `useMemo()` is not necessary. The compiler automatically optimizes re-renders.
1419
1460
1420
-
### 5.5 Narrow Effect Dependencies
1461
+
### 5.6 Narrow Effect Dependencies
1421
1462
1422
1463
**Impact: LOW (minimizes effect re-runs)**
1423
1464
@@ -1458,7 +1499,48 @@ useEffect(() => {
1458
1499
}, [isMobile])
1459
1500
```
1460
1501
1461
-
### 5.6 Subscribe to Derived State
1502
+
### 5.7 Put Interaction Logic in Event Handlers
1503
+
1504
+
**Impact: MEDIUM (avoids effect re-runs and duplicate side effects)**
1505
+
1506
+
If a side effect is triggered by a specific user action (submit, click, drag), run it in that event handler. Do not model the action as state + effect; it makes effects re-run on unrelated changes and can duplicate the action.
**Impact: MEDIUM (prevents stale closures and unnecessary callback recreations)**
1489
1571
@@ -1561,7 +1643,7 @@ function TodoList() {
1561
1643
1562
1644
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, the compiler can automatically optimize some cases, but functional updates are still recommended for correctness and to prevent stale closure bugs.
1563
1645
1564
-
### 5.8 Use Lazy State Initialization
1646
+
### 5.10 Use Lazy State Initialization
1565
1647
1566
1648
**Impact: MEDIUM (wasted computation on every render)**
1567
1649
@@ -1615,7 +1697,7 @@ Use lazy initialization when computing initial values from localStorage/sessionS
1615
1697
1616
1698
For simple primitives (`useState(0)`), direct references (`useState(props.value)`), or cheap literals (`useState({})`), the function form is unnecessary.
1617
1699
1618
-
### 5.9 Use Transitions for Non-Urgent Updates
1700
+
### 5.11 Use Transitions for Non-Urgent Updates
1619
1701
1620
1702
**Impact: MEDIUM (maintains UI responsiveness)**
1621
1703
@@ -1651,6 +1733,75 @@ function ScrollTracker() {
1651
1733
}
1652
1734
```
1653
1735
1736
+
### 5.12 Use useRef for Transient Values
1737
+
1738
+
**Impact: MEDIUM (avoids unnecessary re-renders on frequent updates)**
1739
+
1740
+
When a value changes frequently and you don't want a re-render on every update (e.g., mouse trackers, intervals, transient flags), store it in `useRef` instead of `useState`. Keep component state for UI; use refs for temporary DOM-adjacent values. Updating a ref does not trigger a re-render.
@@ -1880,7 +2031,33 @@ The inline script executes synchronously before showing the element, ensuring th
1880
2031
1881
2032
This pattern is especially useful for theme toggles, user preferences, authentication states, and any client-only data that should render immediately without flashing default values.
1882
2033
1883
-
### 6.6 Use Activity Component for Show/Hide
2034
+
### 6.6 Suppress Expected Hydration Mismatches
2035
+
2036
+
**Impact: LOW-MEDIUM (avoids noisy hydration warnings for known differences)**
2037
+
2038
+
In SSR frameworks (e.g., Next.js), some values are intentionally different on server vs client (random IDs, dates, locale/timezone formatting). For these *expected* mismatches, wrap the dynamic text in an element with `suppressHydrationWarning` to prevent noisy warnings. Do not use this to hide real bugs. Don’t overuse it.
2039
+
2040
+
**Incorrect: known mismatch warnings**
2041
+
2042
+
```tsx
2043
+
function Timestamp() {
2044
+
return <span>{newDate().toLocaleString()}</span>
2045
+
}
2046
+
```
2047
+
2048
+
**Correct: suppress expected mismatch only**
2049
+
2050
+
```tsx
2051
+
function Timestamp() {
2052
+
return (
2053
+
<spansuppressHydrationWarning>
2054
+
{newDate().toLocaleString()}
2055
+
</span>
2056
+
)
2057
+
}
2058
+
```
2059
+
2060
+
### 6.7 Use Activity Component for Show/Hide
1884
2061
1885
2062
**Impact: MEDIUM (preserves state/DOM)**
1886
2063
@@ -1902,7 +2079,7 @@ function Dropdown({ isOpen }: Props) {
1902
2079
1903
2080
Avoids expensive re-renders and state loss.
1904
2081
1905
-
### 6.7 Use Explicit Conditional Rendering
2082
+
### 6.8 Use Explicit Conditional Rendering
1906
2083
1907
2084
**Impact: LOW (prevents rendering 0 or NaN)**
1908
2085
@@ -1938,7 +2115,7 @@ function Badge({ count }: { count: number }) {
1938
2115
// When count = 5, renders: <div><span class="badge">5</span></div>
1939
2116
```
1940
2117
1941
-
### 6.8 Use useTransition Over Manual Loading States
2118
+
### 6.9 Use useTransition Over Manual Loading States
1942
2119
1943
2120
**Impact: LOW (reduces re-renders and improves code clarity)**
Advanced patterns for specific cases that require careful implementation.
2637
2814
2638
-
### 8.1 Store Event Handlers in Refs
2815
+
### 8.1 Initialize App Once, Not Per Mount
2816
+
2817
+
**Impact: LOW-MEDIUM (avoids duplicate init in development)**
2818
+
2819
+
Do not put app-wide initialization that must run once per app load inside `useEffect([])` of a component. Components can remount and effects will re-run. Use a module-level guard or top-level init in the entry module instead.
2820
+
2821
+
**Incorrect: runs twice in dev, re-runs on remount**
`useEffectEvent` provides a cleaner API for the same pattern: it creates a stable function reference that always calls the latest version of the handler.
0 commit comments