my blog https://overreacted.io

update format

+166 -168
+2 -4
app/[slug]/page.js
··· 18 19 export default async function PostPage({ params }) { 20 const file = await readFile("./public/" + params.slug + "/index.md", "utf8"); 21 - let { content, data } = matter(file); 22 - // TODO: change the source instead of this hack. 23 - content = content.replaceAll("```jsx{", "```jsx {"); 24 const discussUrl = `https://x.com/search?q=${encodeURIComponent( 25 `https://overreacted.io/${params.slug}/`, 26 )}`; 27 - const editUrl = `https://github.com/gaearon/overreacted.io/edit/master/public/${encodeURIComponent( 28 params.slug, 29 )}/index.md`; 30 return (
··· 18 19 export default async function PostPage({ params }) { 20 const file = await readFile("./public/" + params.slug + "/index.md", "utf8"); 21 + const { content, data } = matter(file); 22 const discussUrl = `https://x.com/search?q=${encodeURIComponent( 23 `https://overreacted.io/${params.slug}/`, 24 )}`; 25 + const editUrl = `https://github.com/gaearon/overreacted.io/edit/main/public/${encodeURIComponent( 26 params.slug, 27 )}/index.md`; 28 return (
+44 -44
public/a-complete-guide-to-useeffect/index.md
··· 74 75 Here’s a counter. Look at the highlighted line closely: 76 77 - ```jsx{6} 78 function Counter() { 79 const [count, setCount] = useState(0); 80 ··· 102 103 The first time our component renders, the `count` variable we get from `useState()` is `0`. When we call `setCount(1)`, React calls our component again. This time, `count` will be `1`. And so on: 104 105 - ```jsx{3,11,19} 106 // During first render 107 function Counter() { 108 const count = 0; // Returned by useState() ··· 148 149 Look at this example. It shows an alert with the `count` after three seconds: 150 151 - ```jsx{4-8,16-18} 152 function Counter() { 153 const [count, setCount] = useState(0); 154 ··· 204 205 This is not specific to React — regular functions work in a similar way: 206 207 - ```jsx{2} 208 function sayHi(person) { 209 const name = person.name; 210 setTimeout(() => { ··· 226 227 This explains how our event handler captures the `count` at the time of the click. If we apply the same substitution principle, each render “sees” its own `count`: 228 229 - ```jsx{3,15,27} 230 // During first render 231 function Counter() { 232 const count = 0; // Returned by useState() ··· 266 267 So effectively, each render returns its own “version” of `handleAlertClick`. Each of those versions “remembers” its own `count`: 268 269 - ```jsx{6,10,19,23,32,36} 270 // During first render 271 function Counter() { 272 // ... ··· 319 320 Let’s go back to an example from [the docs](https://reactjs.org/docs/hooks-effect.html): 321 322 - ```jsx{4-6} 323 function Counter() { 324 const [count, setCount] = useState(0); 325 ··· 350 351 Each version “sees” the `count` value from the render that it “belongs” to: 352 353 - ```jsx{5-8,17-20,29-32} 354 // During first render 355 function Counter() { 356 // ... ··· 433 434 Let’s try a thought experiment. Consider this code: 435 436 - ```jsx{4-8} 437 function Counter() { 438 const [count, setCount] = useState(0); 439 ··· 493 494 So these two examples are equivalent: 495 496 - ```jsx{4} 497 function Example(props) { 498 useEffect(() => { 499 setTimeout(() => { ··· 504 } 505 ``` 506 507 - ```jsx{2,5} 508 function Example(props) { 509 const counter = props.counter; 510 useEffect(() => { ··· 524 525 Here’s a [version of our counter example](https://codesandbox.io/s/rm7z22qnlp) that replicates the class behavior: 526 527 - ```jsx{3,6-7,9-10} 528 function Example() { 529 const [count, setCount] = useState(0); 530 const latestCount = useRef(count); ··· 588 589 Now the answer is clear! The effect cleanup doesn’t read the “latest” props, whatever that means. It reads props that belong to the render it’s defined in: 590 591 - ```jsx{8-11} 592 // First render, props are {id: 10} 593 function Example() { 594 // ... ··· 650 651 You should think of effects in a similar way. **`useEffect` lets you _synchronize_ things outside of the React tree according to our props and state.** 652 653 - ```jsx{2-4} 654 function Greeting({ name }) { 655 useEffect(() => { 656 document.title = 'Hello, ' + name; ··· 709 710 For example, maybe our component re-renders because of a state change: 711 712 - ```jsx{11-13} 713 function Greeting({ name }) { 714 const [counter, setCounter] = useState(0); 715 ··· 743 744 This is why if you want to avoid re-running effects unnecessarily, you can provide a dependency array (also known as “deps”) argument to `useEffect`: 745 746 - ```jsx{3} 747 useEffect(() => { 748 document.title = 'Hello, ' + name; 749 }, [name]); // Our deps ··· 796 797 If deps contain every value used by the effect, React knows when to re-run it: 798 799 - ```jsx{3} 800 useEffect(() => { 801 document.title = 'Hello, ' + name; 802 }, [name]); ··· 808 809 But if we specified `[]` for this effect, the new effect function wouldn’t run: 810 811 - ```jsx{3} 812 useEffect(() => { 813 document.title = 'Hello, ' + name; 814 }, []); // Wrong: name is missing in deps ··· 822 823 For example, let’s say we’re writing a counter that increments every second. With a class, our intuition is: “Set up the interval once and destroy it once”. Here’s an [example](https://codesandbox.io/s/n5mjzjy9kl) of how we can do it. When we mentally translate this code to `useEffect`, we instinctively add `[]` to the deps. “I want it to run once”, right? 824 825 - ```jsx{9} 826 function Counter() { 827 const [count, setCount] = useState(0); 828 ··· 845 846 In the first render, `count` is `0`. Therefore, `setCount(count + 1)` in the first render’s effect means `setCount(0 + 1)`. **Since we never re-run the effect because of `[]` deps, it will keep calling `setCount(0 + 1)` every second:** 847 848 - ```jsx{8,12,21-22} 849 // First render, state is 0 850 function Counter() { 851 // ... ··· 884 885 Our effect uses `count` — a value inside the component (but outside the effect): 886 887 - ```jsx{1,5} 888 const count = // ... 889 890 useEffect(() => { ··· 909 910 **The first strategy is to fix the dependency array to include _all_ the values inside the component that are used inside the effect.** Let’s include `count` as a dep: 911 912 - ```jsx{3,6} 913 useEffect(() => { 914 const id = setInterval(() => { 915 setCount(count + 1); ··· 920 921 This makes the dependency array correct. It may not be *ideal* but that’s the first issue we needed to fix. Now a change to `count` will re-run the effect, with each next interval referencing `count` from its render in `setCount(count + 1)`: 922 923 - ```jsx{8,12,24,28} 924 // First render, state is 0 925 function Counter() { 926 // ... ··· 972 973 We want to get rid of the `count` dependency in our effect. 974 975 - ```jsx{3,6} 976 useEffect(() => { 977 const id = setInterval(() => { 978 setCount(count + 1); ··· 983 984 To do this, we need to ask ourselves: **what are we using `count` for?** It seems like we only use it for the `setCount` call. In that case, we don’t actually need `count` in the scope at all. When we want to update state based on the previous state, we can use the [functional updater form](https://reactjs.org/docs/hooks-reference.html#functional-updates) of `setState`: 985 986 - ```jsx{3} 987 useEffect(() => { 988 const id = setInterval(() => { 989 setCount(c => c + 1); ··· 1020 1021 Let’s modify the previous example to have two state variables: `count` and `step`. Our interval will increment the count by the value of the `step` input: 1022 1023 - ```jsx{7,10} 1024 function Counter() { 1025 const [count, setCount] = useState(0); 1026 const [step, setStep] = useState(1); ··· 1055 1056 Let’s trade the `step` dependency for a `dispatch` dependency in our effect: 1057 1058 - ```jsx{1,6,9} 1059 const [state, dispatch] = useReducer(reducer, initialState); 1060 const { count, step } = state; 1061 ··· 1077 1078 Instead of reading the state *inside* an effect, it dispatches an *action* that encodes the information about *what happened*. This allows our effect to stay decoupled from the `step` state. Our effect doesn’t care *how* we update the state, it just tells us about *what happened*. And the reducer centralizes the update logic: 1079 1080 - ```jsx{8,9} 1081 const initialState = { 1082 count: 0, 1083 step: 1, ··· 1103 1104 In fact, we can! We can put *the reducer itself* inside our component to read props: 1105 1106 - ```jsx{1,6} 1107 function Counter({ step }) { 1108 const [count, dispatch] = useReducer(reducer, 0); 1109 ··· 1138 1139 A common mistake is to think functions shouldn’t be dependencies. For example, this seems like it could work: 1140 1141 - ```jsx{13} 1142 function SearchResults() { 1143 const [data, setData] = useState({ hits: [] }); 1144 ··· 1186 1187 Now let’s say we later use some state or prop in one of these functions: 1188 1189 - ```jsx{6} 1190 function SearchResults() { 1191 const [query, setQuery] = useState('react'); 1192 ··· 1213 1214 Luckily, there is an easy solution to this problem. **If you only use some functions *inside* an effect, move them directly *into* that effect:** 1215 1216 - ```jsx{4-12} 1217 function SearchResults() { 1218 // ... 1219 useEffect(() => { ··· 1239 1240 If we later edit `getFetchUrl` to use the `query` state, we’re much more likely to notice that we’re editing it *inside* an effect — and therefore, we need to add `query` to the effect dependencies: 1241 1242 - ```jsx{6,15} 1243 function SearchResults() { 1244 const [query, setQuery] = useState('react'); 1245 ··· 1302 1303 On the other hand, if you’re “honest” about the effect dependencies, you may run into a problem. Since both our effects depend on `getFetchUrl` **(which is different on every render)**, our dependency arrays are useless: 1304 1305 - ```jsx{2-5} 1306 function SearchResults() { 1307 // 🔴 Re-triggers all effects on every render 1308 function getFetchUrl(query) { ··· 1329 1330 **First of all, if a function doesn’t use anything from the component scope, you can hoist it outside the component and then freely use it inside your effects:** 1331 1332 - ```jsx{1-4} 1333 // ✅ Not affected by the data flow 1334 function getFetchUrl(query) { 1335 return 'https://hn.algolia.com/api/v1/search?query=' + query; ··· 1355 Alternatively, you can wrap it into the [`useCallback` Hook](https://reactjs.org/docs/hooks-reference.html#usecallback): 1356 1357 1358 - ```jsx{2-5} 1359 function SearchResults() { 1360 // ✅ Preserves identity when its own deps are the same 1361 const getFetchUrl = useCallback((query) => { ··· 1382 1383 We'll immediately see that it's missing a `query` dependency: 1384 1385 - ```jsx{5} 1386 function SearchResults() { 1387 const [query, setQuery] = useState('react'); 1388 const getFetchUrl = useCallback(() => { // No query argument ··· 1394 1395 If I fix my `useCallback` deps to include `query`, any effect with `getFetchUrl` in deps will re-run whenever the `query` changes: 1396 1397 - ```jsx{4-7} 1398 function SearchResults() { 1399 const [query, setQuery] = useState('react'); 1400 ··· 1416 1417 This is just a consequence of embracing the data flow and the synchronization mindset. **The same solution works for function props passed from parents:** 1418 1419 - ```jsx{4-8} 1420 function Parent() { 1421 const [query, setQuery] = useState('react'); 1422 ··· 1446 1447 Interestingly, this pattern is broken with classes in a way that really shows the difference between the effect and lifecycle paradigms. Consider this translation: 1448 1449 - ```jsx{5-8,18-20} 1450 class Parent extends Component { 1451 state = { 1452 query: 'react' ··· 1475 1476 You might be thinking: “Come on Dan, we all know that `useEffect` is like `componentDidMount` and `componentDidUpdate` combined, you can’t keep beating that drum!” **Yet this doesn’t work even with `componentDidUpdate`:** 1477 1478 - ```jsx{8-13} 1479 class Child extends Component { 1480 state = { 1481 data: null ··· 1515 1516 The only real solution to this conundrum with classes is to bite the bullet and pass the `query` itself into the `Child` component. The `Child` doesn’t actually end up *using* the `query`, but it can trigger a refetch when it changes: 1517 1518 - ```jsx{10,22-24} 1519 class Parent extends Component { 1520 state = { 1521 query: 'react' ··· 1591 1592 As you probably know, this code is buggy. It doesn’t handle updates. So the second classic example you could find online is something like this: 1593 1594 - ```jsx{8-12} 1595 class Article extends Component { 1596 state = { 1597 article: null ··· 1622 1623 Alternatively, the easiest stopgap approach is to track it with a boolean: 1624 1625 - ```jsx{5,9,16-18} 1626 function Article({ id }) { 1627 const [article, setArticle] = useState(null); 1628
··· 74 75 Here’s a counter. Look at the highlighted line closely: 76 77 + ```jsx {6} 78 function Counter() { 79 const [count, setCount] = useState(0); 80 ··· 102 103 The first time our component renders, the `count` variable we get from `useState()` is `0`. When we call `setCount(1)`, React calls our component again. This time, `count` will be `1`. And so on: 104 105 + ```jsx {3,11,19} 106 // During first render 107 function Counter() { 108 const count = 0; // Returned by useState() ··· 148 149 Look at this example. It shows an alert with the `count` after three seconds: 150 151 + ```jsx {4-8,16-18} 152 function Counter() { 153 const [count, setCount] = useState(0); 154 ··· 204 205 This is not specific to React — regular functions work in a similar way: 206 207 + ```jsx {2} 208 function sayHi(person) { 209 const name = person.name; 210 setTimeout(() => { ··· 226 227 This explains how our event handler captures the `count` at the time of the click. If we apply the same substitution principle, each render “sees” its own `count`: 228 229 + ```jsx {3,15,27} 230 // During first render 231 function Counter() { 232 const count = 0; // Returned by useState() ··· 266 267 So effectively, each render returns its own “version” of `handleAlertClick`. Each of those versions “remembers” its own `count`: 268 269 + ```jsx {6,10,19,23,32,36} 270 // During first render 271 function Counter() { 272 // ... ··· 319 320 Let’s go back to an example from [the docs](https://reactjs.org/docs/hooks-effect.html): 321 322 + ```jsx {4-6} 323 function Counter() { 324 const [count, setCount] = useState(0); 325 ··· 350 351 Each version “sees” the `count` value from the render that it “belongs” to: 352 353 + ```jsx {5-8,17-20,29-32} 354 // During first render 355 function Counter() { 356 // ... ··· 433 434 Let’s try a thought experiment. Consider this code: 435 436 + ```jsx {4-8} 437 function Counter() { 438 const [count, setCount] = useState(0); 439 ··· 493 494 So these two examples are equivalent: 495 496 + ```jsx {4} 497 function Example(props) { 498 useEffect(() => { 499 setTimeout(() => { ··· 504 } 505 ``` 506 507 + ```jsx {2,5} 508 function Example(props) { 509 const counter = props.counter; 510 useEffect(() => { ··· 524 525 Here’s a [version of our counter example](https://codesandbox.io/s/rm7z22qnlp) that replicates the class behavior: 526 527 + ```jsx {3,6-7,9-10} 528 function Example() { 529 const [count, setCount] = useState(0); 530 const latestCount = useRef(count); ··· 588 589 Now the answer is clear! The effect cleanup doesn’t read the “latest” props, whatever that means. It reads props that belong to the render it’s defined in: 590 591 + ```jsx {8-11} 592 // First render, props are {id: 10} 593 function Example() { 594 // ... ··· 650 651 You should think of effects in a similar way. **`useEffect` lets you _synchronize_ things outside of the React tree according to our props and state.** 652 653 + ```jsx {2-4} 654 function Greeting({ name }) { 655 useEffect(() => { 656 document.title = 'Hello, ' + name; ··· 709 710 For example, maybe our component re-renders because of a state change: 711 712 + ```jsx {11-13} 713 function Greeting({ name }) { 714 const [counter, setCounter] = useState(0); 715 ··· 743 744 This is why if you want to avoid re-running effects unnecessarily, you can provide a dependency array (also known as “deps”) argument to `useEffect`: 745 746 + ```jsx {3} 747 useEffect(() => { 748 document.title = 'Hello, ' + name; 749 }, [name]); // Our deps ··· 796 797 If deps contain every value used by the effect, React knows when to re-run it: 798 799 + ```jsx {3} 800 useEffect(() => { 801 document.title = 'Hello, ' + name; 802 }, [name]); ··· 808 809 But if we specified `[]` for this effect, the new effect function wouldn’t run: 810 811 + ```jsx {3} 812 useEffect(() => { 813 document.title = 'Hello, ' + name; 814 }, []); // Wrong: name is missing in deps ··· 822 823 For example, let’s say we’re writing a counter that increments every second. With a class, our intuition is: “Set up the interval once and destroy it once”. Here’s an [example](https://codesandbox.io/s/n5mjzjy9kl) of how we can do it. When we mentally translate this code to `useEffect`, we instinctively add `[]` to the deps. “I want it to run once”, right? 824 825 + ```jsx {9} 826 function Counter() { 827 const [count, setCount] = useState(0); 828 ··· 845 846 In the first render, `count` is `0`. Therefore, `setCount(count + 1)` in the first render’s effect means `setCount(0 + 1)`. **Since we never re-run the effect because of `[]` deps, it will keep calling `setCount(0 + 1)` every second:** 847 848 + ```jsx {8,12,21-22} 849 // First render, state is 0 850 function Counter() { 851 // ... ··· 884 885 Our effect uses `count` — a value inside the component (but outside the effect): 886 887 + ```jsx {1,5} 888 const count = // ... 889 890 useEffect(() => { ··· 909 910 **The first strategy is to fix the dependency array to include _all_ the values inside the component that are used inside the effect.** Let’s include `count` as a dep: 911 912 + ```jsx {3,6} 913 useEffect(() => { 914 const id = setInterval(() => { 915 setCount(count + 1); ··· 920 921 This makes the dependency array correct. It may not be *ideal* but that’s the first issue we needed to fix. Now a change to `count` will re-run the effect, with each next interval referencing `count` from its render in `setCount(count + 1)`: 922 923 + ```jsx {8,12,24,28} 924 // First render, state is 0 925 function Counter() { 926 // ... ··· 972 973 We want to get rid of the `count` dependency in our effect. 974 975 + ```jsx {3,6} 976 useEffect(() => { 977 const id = setInterval(() => { 978 setCount(count + 1); ··· 983 984 To do this, we need to ask ourselves: **what are we using `count` for?** It seems like we only use it for the `setCount` call. In that case, we don’t actually need `count` in the scope at all. When we want to update state based on the previous state, we can use the [functional updater form](https://reactjs.org/docs/hooks-reference.html#functional-updates) of `setState`: 985 986 + ```jsx {3} 987 useEffect(() => { 988 const id = setInterval(() => { 989 setCount(c => c + 1); ··· 1020 1021 Let’s modify the previous example to have two state variables: `count` and `step`. Our interval will increment the count by the value of the `step` input: 1022 1023 + ```jsx {7,10} 1024 function Counter() { 1025 const [count, setCount] = useState(0); 1026 const [step, setStep] = useState(1); ··· 1055 1056 Let’s trade the `step` dependency for a `dispatch` dependency in our effect: 1057 1058 + ```jsx {1,6,9} 1059 const [state, dispatch] = useReducer(reducer, initialState); 1060 const { count, step } = state; 1061 ··· 1077 1078 Instead of reading the state *inside* an effect, it dispatches an *action* that encodes the information about *what happened*. This allows our effect to stay decoupled from the `step` state. Our effect doesn’t care *how* we update the state, it just tells us about *what happened*. And the reducer centralizes the update logic: 1079 1080 + ```jsx {8,9} 1081 const initialState = { 1082 count: 0, 1083 step: 1, ··· 1103 1104 In fact, we can! We can put *the reducer itself* inside our component to read props: 1105 1106 + ```jsx {1,6} 1107 function Counter({ step }) { 1108 const [count, dispatch] = useReducer(reducer, 0); 1109 ··· 1138 1139 A common mistake is to think functions shouldn’t be dependencies. For example, this seems like it could work: 1140 1141 + ```jsx {13} 1142 function SearchResults() { 1143 const [data, setData] = useState({ hits: [] }); 1144 ··· 1186 1187 Now let’s say we later use some state or prop in one of these functions: 1188 1189 + ```jsx {6} 1190 function SearchResults() { 1191 const [query, setQuery] = useState('react'); 1192 ··· 1213 1214 Luckily, there is an easy solution to this problem. **If you only use some functions *inside* an effect, move them directly *into* that effect:** 1215 1216 + ```jsx {4-12} 1217 function SearchResults() { 1218 // ... 1219 useEffect(() => { ··· 1239 1240 If we later edit `getFetchUrl` to use the `query` state, we’re much more likely to notice that we’re editing it *inside* an effect — and therefore, we need to add `query` to the effect dependencies: 1241 1242 + ```jsx {6,15} 1243 function SearchResults() { 1244 const [query, setQuery] = useState('react'); 1245 ··· 1302 1303 On the other hand, if you’re “honest” about the effect dependencies, you may run into a problem. Since both our effects depend on `getFetchUrl` **(which is different on every render)**, our dependency arrays are useless: 1304 1305 + ```jsx {2-5} 1306 function SearchResults() { 1307 // 🔴 Re-triggers all effects on every render 1308 function getFetchUrl(query) { ··· 1329 1330 **First of all, if a function doesn’t use anything from the component scope, you can hoist it outside the component and then freely use it inside your effects:** 1331 1332 + ```jsx {1-4} 1333 // ✅ Not affected by the data flow 1334 function getFetchUrl(query) { 1335 return 'https://hn.algolia.com/api/v1/search?query=' + query; ··· 1355 Alternatively, you can wrap it into the [`useCallback` Hook](https://reactjs.org/docs/hooks-reference.html#usecallback): 1356 1357 1358 + ```jsx {2-5} 1359 function SearchResults() { 1360 // ✅ Preserves identity when its own deps are the same 1361 const getFetchUrl = useCallback((query) => { ··· 1382 1383 We'll immediately see that it's missing a `query` dependency: 1384 1385 + ```jsx {5} 1386 function SearchResults() { 1387 const [query, setQuery] = useState('react'); 1388 const getFetchUrl = useCallback(() => { // No query argument ··· 1394 1395 If I fix my `useCallback` deps to include `query`, any effect with `getFetchUrl` in deps will re-run whenever the `query` changes: 1396 1397 + ```jsx {4-7} 1398 function SearchResults() { 1399 const [query, setQuery] = useState('react'); 1400 ··· 1416 1417 This is just a consequence of embracing the data flow and the synchronization mindset. **The same solution works for function props passed from parents:** 1418 1419 + ```jsx {4-8} 1420 function Parent() { 1421 const [query, setQuery] = useState('react'); 1422 ··· 1446 1447 Interestingly, this pattern is broken with classes in a way that really shows the difference between the effect and lifecycle paradigms. Consider this translation: 1448 1449 + ```jsx {5-8,18-20} 1450 class Parent extends Component { 1451 state = { 1452 query: 'react' ··· 1475 1476 You might be thinking: “Come on Dan, we all know that `useEffect` is like `componentDidMount` and `componentDidUpdate` combined, you can’t keep beating that drum!” **Yet this doesn’t work even with `componentDidUpdate`:** 1477 1478 + ```jsx {8-13} 1479 class Child extends Component { 1480 state = { 1481 data: null ··· 1515 1516 The only real solution to this conundrum with classes is to bite the bullet and pass the `query` itself into the `Child` component. The `Child` doesn’t actually end up *using* the `query`, but it can trigger a refetch when it changes: 1517 1518 + ```jsx {10,22-24} 1519 class Parent extends Component { 1520 state = { 1521 query: 'react' ··· 1591 1592 As you probably know, this code is buggy. It doesn’t handle updates. So the second classic example you could find online is something like this: 1593 1594 + ```jsx {8-12} 1595 class Article extends Component { 1596 state = { 1597 article: null ··· 1622 1623 Alternatively, the easiest stopgap approach is to track it with a boolean: 1624 1625 + ```jsx {5,9,16-18} 1626 function Article({ id }) { 1627 const [article, setArticle] = useState(null); 1628
+11 -11
public/algebraic-effects-for-the-rest-of-us/index.md
··· 35 36 Let’s recap `try / catch` first. Say you have a function that throws. Maybe there’s a bunch of functions between it and the `catch` block: 37 38 - ```jsx{4,19} 39 function getName(user) { 40 let name = user.name; 41 if (name === null) { ··· 70 71 This is an example written in a hypothetical JavaScript dialect (let’s call it ES2025 just for kicks) that lets us *recover* from a missing `user.name`: 72 73 - ```jsx{4,19-21} 74 function getName(user) { 75 let name = user.name; 76 if (name === null) { ··· 103 104 Instead of throwing an error, we *perform an effect*. Just like we can `throw` any value, we can pass any value to `perform`. In this example, I’m passing a string, but it could be an object, or any other data type: 105 106 - ```jsx{4} 107 function getName(user) { 108 let name = user.name; 109 if (name === null) { ··· 115 116 When we `throw` an error, the engine looks for the closest `try / catch` error handler up the call stack. Similarly, when we `perform` an effect, the engine would search for the closest `try / handle` *effect handler* up the call stack: 117 118 - ```jsx{3} 119 try { 120 makeFriends(arya, gendry); 121 } handle (effect) { ··· 127 128 This effect lets us decide how to handle the case where a name is missing. The novel part here (compared to exceptions) is the hypothetical `resume with`: 129 130 - ```jsx{5} 131 try { 132 makeFriends(arya, gendry); 133 } handle (effect) { ··· 139 140 This is the part you can’t do with `try / catch`. It lets us **jump back to where we performed the effect, and pass something back to it from the handler**. 🤯 141 142 - ```jsx{4,6,16,18} 143 function getName(user) { 144 let name = user.name; 145 if (name === null) { ··· 194 195 For a moment, let’s forget about `async / await` and get back to our example: 196 197 - ```jsx{4,19-21} 198 function getName(user) { 199 let name = user.name; 200 if (name === null) { ··· 223 224 It turns out, we can call `resume with` asynchronously from our effect handler without making any changes to `getName` or `makeFriends`: 225 226 - ```jsx{19-23} 227 function getName(user) { 228 let name = user.name; 229 if (name === null) { ··· 264 265 They let you write code that focuses on *what* you’re doing: 266 267 - ```jsx{2,3,5,7,12} 268 function enumerateFiles(dir) { 269 const contents = perform OpenDirectory(dir); 270 perform Log('Enumerating files in ', dir); ··· 282 283 And later wrap it with something that specifies *how*: 284 285 - ```jsx{6-7,9-11,13-14} 286 let files = []; 287 try { 288 enumerateFiles('C:\\'); ··· 323 324 Effect handlers let us decouple the program logic from its concrete effect implementations without too much ceremony or boilerplate code. For example, we could completely override the behavior in tests to use a fake filesystem and to snapshot logs instead of outputting them to the console: 325 326 - ```jsx{19-23} 327 import { withFakeFileSystem } from 'fake-fs'; 328 329 function withLogSnapshot(fn) {
··· 35 36 Let’s recap `try / catch` first. Say you have a function that throws. Maybe there’s a bunch of functions between it and the `catch` block: 37 38 + ```jsx {4,19} 39 function getName(user) { 40 let name = user.name; 41 if (name === null) { ··· 70 71 This is an example written in a hypothetical JavaScript dialect (let’s call it ES2025 just for kicks) that lets us *recover* from a missing `user.name`: 72 73 + ```jsx {4,19-21} 74 function getName(user) { 75 let name = user.name; 76 if (name === null) { ··· 103 104 Instead of throwing an error, we *perform an effect*. Just like we can `throw` any value, we can pass any value to `perform`. In this example, I’m passing a string, but it could be an object, or any other data type: 105 106 + ```jsx {4} 107 function getName(user) { 108 let name = user.name; 109 if (name === null) { ··· 115 116 When we `throw` an error, the engine looks for the closest `try / catch` error handler up the call stack. Similarly, when we `perform` an effect, the engine would search for the closest `try / handle` *effect handler* up the call stack: 117 118 + ```jsx {3} 119 try { 120 makeFriends(arya, gendry); 121 } handle (effect) { ··· 127 128 This effect lets us decide how to handle the case where a name is missing. The novel part here (compared to exceptions) is the hypothetical `resume with`: 129 130 + ```jsx {5} 131 try { 132 makeFriends(arya, gendry); 133 } handle (effect) { ··· 139 140 This is the part you can’t do with `try / catch`. It lets us **jump back to where we performed the effect, and pass something back to it from the handler**. 🤯 141 142 + ```jsx {4,6,16,18} 143 function getName(user) { 144 let name = user.name; 145 if (name === null) { ··· 194 195 For a moment, let’s forget about `async / await` and get back to our example: 196 197 + ```jsx {4,19-21} 198 function getName(user) { 199 let name = user.name; 200 if (name === null) { ··· 223 224 It turns out, we can call `resume with` asynchronously from our effect handler without making any changes to `getName` or `makeFriends`: 225 226 + ```jsx {19-23} 227 function getName(user) { 228 let name = user.name; 229 if (name === null) { ··· 264 265 They let you write code that focuses on *what* you’re doing: 266 267 + ```jsx {2,3,5,7,12} 268 function enumerateFiles(dir) { 269 const contents = perform OpenDirectory(dir); 270 perform Log('Enumerating files in ', dir); ··· 282 283 And later wrap it with something that specifies *how*: 284 285 + ```jsx {6-7,9-11,13-14} 286 let files = []; 287 try { 288 enumerateFiles('C:\\'); ··· 323 324 Effect handlers let us decouple the program logic from its concrete effect implementations without too much ceremony or boilerplate code. For example, we could completely override the behavior in tests to use a fake filesystem and to snapshot logs instead of outputting them to the console: 325 326 + ```jsx {19-23} 327 import { withFakeFileSystem } from 'fake-fs'; 328 329 function withLogSnapshot(fn) {
+4 -4
public/before-you-memo/index.md
··· 53 54 If you look at the rendering code closer, you'll notice only a part of the returned tree actually cares about the current `color`: 55 56 - ```jsx{2,5-6} 57 export default function App() { 58 let [color, setColor] = useState('red'); 59 return ( ··· 68 69 So let's extract that part into a `Form` component and move state _down_ into it: 70 71 - ```jsx{4,11,14,15} 72 export default function App() { 73 return ( 74 <> ··· 97 98 The above solution doesn't work if the piece of state is used somewhere *above* the expensive tree. For example, let's say we put the `color` on the *parent* `<div>`: 99 100 - ```jsx{2,4} 101 export default function App() { 102 let [color, setColor] = useState('red'); 103 return ( ··· 126 127 The answer is remarkably plain: 128 129 - ```jsx{4,5,10,15} 130 export default function App() { 131 return ( 132 <ColorPicker>
··· 53 54 If you look at the rendering code closer, you'll notice only a part of the returned tree actually cares about the current `color`: 55 56 + ```jsx {2,5-6} 57 export default function App() { 58 let [color, setColor] = useState('red'); 59 return ( ··· 68 69 So let's extract that part into a `Form` component and move state _down_ into it: 70 71 + ```jsx {4,11,14,15} 72 export default function App() { 73 return ( 74 <> ··· 97 98 The above solution doesn't work if the piece of state is used somewhere *above* the expensive tree. For example, let's say we put the `color` on the *parent* `<div>`: 99 100 + ```jsx {2,4} 101 export default function App() { 102 let [color, setColor] = useState('red'); 103 return ( ··· 126 127 The answer is remarkably plain: 128 129 + ```jsx {4,5,10,15} 130 export default function App() { 131 return ( 132 <ColorPicker>
+7 -7
public/how-are-function-components-different-from-classes/index.md
··· 112 113 Let’s look closely at the `showMessage` method in our class: 114 115 - ```jsx{3} 116 class ProfilePage extends React.Component { 117 showMessage = () => { 118 alert('Followed ' + this.props.user); ··· 137 138 One way to do it would be to read `this.props` early during the event, and then explicitly pass them through into the timeout completion handler: 139 140 - ```jsx{2,7} 141 class ProfilePage extends React.Component { 142 showMessage = (user) => { 143 alert('Followed ' + user); ··· 162 163 Perhaps, we could *bind* the methods in the constructor? 164 165 - ```jsx{4-5} 166 class ProfilePage extends React.Component { 167 constructor(props) { 168 super(props); ··· 190 191 This means that if you close over props or state from a particular render, you can always count on them staying exactly the same: 192 193 - ```jsx{3,4,9} 194 class ProfilePage extends React.Component { 195 render() { 196 // Capture the props! ··· 246 247 It’s a bit more obvious if you destructure `props` in the function definition: 248 249 - ```jsx{1,3} 250 function ProfilePage({ user }) { 251 const showMessage = () => { 252 alert('Followed ' + user); ··· 329 330 By default, React doesn’t create refs for latest props or state in function components. In many cases you don’t need them, and it would be wasted work to assign them. However, you can track the value manually if you’d like: 331 332 - ```jsx{3,6,15} 333 function MessageThread() { 334 const [message, setMessage] = useState(''); 335 const latestMessage = useRef(''); ··· 354 355 Generally, you should avoid reading or setting refs *during* rendering because they’re mutable. We want to keep the rendering predictable. **However, if we want to get the latest value of a particular prop or state, it can be annoying to update the ref manually.** We could automate it by using an effect: 356 357 - ```jsx{4-8,11} 358 function MessageThread() { 359 const [message, setMessage] = useState(''); 360
··· 112 113 Let’s look closely at the `showMessage` method in our class: 114 115 + ```jsx {3} 116 class ProfilePage extends React.Component { 117 showMessage = () => { 118 alert('Followed ' + this.props.user); ··· 137 138 One way to do it would be to read `this.props` early during the event, and then explicitly pass them through into the timeout completion handler: 139 140 + ```jsx {2,7} 141 class ProfilePage extends React.Component { 142 showMessage = (user) => { 143 alert('Followed ' + user); ··· 162 163 Perhaps, we could *bind* the methods in the constructor? 164 165 + ```jsx {4-5} 166 class ProfilePage extends React.Component { 167 constructor(props) { 168 super(props); ··· 190 191 This means that if you close over props or state from a particular render, you can always count on them staying exactly the same: 192 193 + ```jsx {3,4,9} 194 class ProfilePage extends React.Component { 195 render() { 196 // Capture the props! ··· 246 247 It’s a bit more obvious if you destructure `props` in the function definition: 248 249 + ```jsx {1,3} 250 function ProfilePage({ user }) { 251 const showMessage = () => { 252 alert('Followed ' + user); ··· 329 330 By default, React doesn’t create refs for latest props or state in function components. In many cases you don’t need them, and it would be wasted work to assign them. However, you can track the value manually if you’d like: 331 332 + ```jsx {3,6,15} 333 function MessageThread() { 334 const [message, setMessage] = useState(''); 335 const latestMessage = useRef(''); ··· 354 355 Generally, you should avoid reading or setting refs *during* rendering because they’re mutable. We want to keep the rendering predictable. **However, if we want to get the latest value of a particular prop or state, it can be annoying to update the ref manually.** We could automate it by using an effect: 356 357 + ```jsx {4-8,11} 358 function MessageThread() { 359 const [message, setMessage] = useState(''); 360
+7 -7
public/how-does-react-tell-a-class-from-a-function/index.md
··· 77 78 First, we need to understand why it’s important to treat functions and classes differently. Note how we use the `new` operator when calling a class: 79 80 - ```jsx{5} 81 // If Greeting is a function 82 const result = Greeting(props); // <p>Hello</p> 83 ··· 116 117 The `new` operator also makes anything we put on `Person.prototype` available on the `fred` object: 118 119 - ```jsx{4-6,9} 120 function Person(name) { 121 this.name = name; 122 } ··· 244 245 This behavior is intentional and follows from the design of arrow functions. One of the main perks of arrow functions is that they *don’t* have their own `this` value — instead, `this` is resolved from the closest regular function: 246 247 - ```jsx{2,6,7} 248 class Friends extends React.Component { 249 render() { 250 const friends = this.props.friends; ··· 297 298 However, JavaScript also allows a function called with `new` to *override* the return value of `new` by returning some other object. Presumably, this was considered useful for patterns like pooling where we want to reuse instances: 299 300 - ```jsx{1-2,7-8,17-18} 301 // Created lazily 302 var zeroVector = null; 303 ··· 371 372 What’s the `prototype` property on a function or a class, then? **It’s the `__proto__` given to all objects `new`ed with that class or a function!** 373 374 - ```jsx{8} 375 function Person(name) { 376 this.name = name; 377 } ··· 409 410 With classes, you’re not exposed directly to this mechanism, but `extends` also works on top of the good old prototype chain. That’s how our React class instance gets access to methods like `setState`: 411 412 - ```jsx{1,9,13} 413 class Greeting extends React.Component { 414 render() { 415 return <p>Hello</p>; ··· 447 448 Since the `__proto__` chain mirrors the class hierarchy, we can check whether a `Greeting` extends `React.Component` by starting with `Greeting.prototype`, and then following down its `__proto__` chain: 449 450 - ```jsx{3,4} 451 // `__proto__` chain 452 new Greeting() 453 → Greeting.prototype // 🕵️ We start here
··· 77 78 First, we need to understand why it’s important to treat functions and classes differently. Note how we use the `new` operator when calling a class: 79 80 + ```jsx {5} 81 // If Greeting is a function 82 const result = Greeting(props); // <p>Hello</p> 83 ··· 116 117 The `new` operator also makes anything we put on `Person.prototype` available on the `fred` object: 118 119 + ```jsx {4-6,9} 120 function Person(name) { 121 this.name = name; 122 } ··· 244 245 This behavior is intentional and follows from the design of arrow functions. One of the main perks of arrow functions is that they *don’t* have their own `this` value — instead, `this` is resolved from the closest regular function: 246 247 + ```jsx {2,6,7} 248 class Friends extends React.Component { 249 render() { 250 const friends = this.props.friends; ··· 297 298 However, JavaScript also allows a function called with `new` to *override* the return value of `new` by returning some other object. Presumably, this was considered useful for patterns like pooling where we want to reuse instances: 299 300 + ```jsx {1-2,7-8,17-18} 301 // Created lazily 302 var zeroVector = null; 303 ··· 371 372 What’s the `prototype` property on a function or a class, then? **It’s the `__proto__` given to all objects `new`ed with that class or a function!** 373 374 + ```jsx {8} 375 function Person(name) { 376 this.name = name; 377 } ··· 409 410 With classes, you’re not exposed directly to this mechanism, but `extends` also works on top of the good old prototype chain. That’s how our React class instance gets access to methods like `setState`: 411 412 + ```jsx {1,9,13} 413 class Greeting extends React.Component { 414 render() { 415 return <p>Hello</p>; ··· 447 448 Since the `__proto__` chain mirrors the class hierarchy, we can check whether a `Greeting` extends `React.Component` by starting with `Greeting.prototype`, and then following down its `__proto__` chain: 449 450 + ```jsx {3,4} 451 // `__proto__` chain 452 new Greeting() 453 → Greeting.prototype // 🕵️ We start here
+3 -3
public/how-does-setstate-know-what-to-do/index.md
··· 7 8 When you call `setState` in a component, what do you think happens? 9 10 - ```jsx{11} 11 import React from 'react'; 12 import ReactDOM from 'react-dom'; 13 ··· 112 **The answer is that every renderer sets a special field on the created class.** This field is called `updater`. It’s not something *you* would set — rather, it’s something React DOM, React DOM Server or React Native set right after creating an instance of your class: 113 114 115 - ```jsx{4,9,14} 116 // Inside React DOM 117 const inst = new YourComponent(); 118 inst.props = props; ··· 172 173 And individual renderers set the dispatcher before rendering your component: 174 175 - ```jsx{3,8-9} 176 // In React DOM 177 const prevDispatcher = React.__currentDispatcher; 178 React.__currentDispatcher = ReactDOMDispatcher;
··· 7 8 When you call `setState` in a component, what do you think happens? 9 10 + ```jsx {11} 11 import React from 'react'; 12 import ReactDOM from 'react-dom'; 13 ··· 112 **The answer is that every renderer sets a special field on the created class.** This field is called `updater`. It’s not something *you* would set — rather, it’s something React DOM, React DOM Server or React Native set right after creating an instance of your class: 113 114 115 + ```jsx {4,9,14} 116 // Inside React DOM 117 const inst = new YourComponent(); 118 inst.props = props; ··· 172 173 And individual renderers set the dispatcher before rendering your component: 174 175 + ```jsx {3,8-9} 176 // In React DOM 177 const prevDispatcher = React.__currentDispatcher; 178 React.__currentDispatcher = ReactDOMDispatcher;
+17 -17
public/making-setinterval-declarative-with-react-hooks/index.md
··· 30 31 Without further ado, here’s a counter that increments every second: 32 33 - ```jsx{6-9} 34 import React, { useState, useEffect, useRef } from 'react'; 35 36 function Counter() { ··· 128 129 So how would you do this with `setInterval` in a class? I ended up with this: 130 131 - ```jsx{7-26} 132 class Counter extends React.Component { 133 state = { 134 count: 0, ··· 179 180 <font size="50">🥁🥁🥁</font> 181 182 - ```jsx{5-8} 183 function Counter() { 184 let [count, setCount] = useState(0); 185 let [delay, setDelay] = useState(1000); ··· 208 209 Unlike the class version, there is no complexity gap for “upgrading” the `useInterval` Hook example to have a dynamically adjusted delay: 210 211 - ```jsx{4,9} 212 // Constant delay 213 useInterval(() => { 214 setCount(count + 1); ··· 226 227 What if I want to temporarily *pause* my interval? I can do this with state too: 228 229 - ```jsx{6} 230 const [delay, setDelay] = useState(1000); 231 const [isRunning, setIsRunning] = useState(true); 232 ··· 260 261 Now I want an interval that increments it every second. It’s a [side effect that needs cleanup](https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup) so I’m going to `useEffect()` and return the cleanup function: 262 263 - ```jsx{4-9} 264 function Counter() { 265 let [count, setCount] = useState(0); 266 ··· 304 305 You might know that `useEffect()` lets us [*opt out*](https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects) of re-applying effects. You can specify a dependency array as a second argument, and React will only re-run the effect if something in that array changes: 306 307 - ```jsx{3} 308 useEffect(() => { 309 document.title = `You clicked ${count} times`; 310 }, [count]); ··· 316 317 In the first attempt, our problem was that re-running the effects caused our timer to get cleared too early. We can try to fix it by never re-running them: 318 319 - ```jsx{9} 320 function Counter() { 321 let [count, setCount] = useState(0); 322 ··· 364 365 Hooks let us apply the same declarative approach to effects: 366 367 - ```jsx{4} 368 // Describes every interval state 369 useInterval(() => { 370 setCount(count + 1); ··· 420 421 `useRef()` returns a plain object with a mutable `current` property that’s shared between renders. We can save the *latest* interval callback into it: 422 423 - ```jsx{8} 424 function callback() { 425 // Can read fresh props, state, etc. 426 setCount(count + 1); ··· 434 435 And then we can read and call it from inside our interval: 436 437 - ```jsx{3,8} 438 useEffect(() => { 439 function tick() { 440 savedCallback.current(); ··· 449 450 Here’s a complete working solution: 451 452 - ```jsx{10,15} 453 function Counter() { 454 const [count, setCount] = useState(0); 455 const savedCallback = useRef(); ··· 487 488 Ideally, I just want to write this: 489 490 - ```jsx{4-6} 491 function Counter() { 492 const [count, setCount] = useState(0); 493 ··· 534 535 Now that the `delay` can change between renders, I need to declare it in the dependencies of my interval effect: 536 537 - ```jsx{8} 538 useEffect(() => { 539 function tick() { 540 savedCallback.current(); ··· 586 587 Say we want to be able to pause our interval by passing `null` as the `delay`: 588 589 - ```jsx{6} 590 const [delay, setDelay] = useState(1000); 591 const [isRunning, setIsRunning] = useState(true); 592 ··· 597 598 How do we implement this? The answer is: by not setting up an interval. 599 600 - ```jsx{6} 601 useEffect(() => { 602 function tick() { 603 savedCallback.current(); ··· 622 623 ![Counter that automatically speeds up](./counter_inception.gif) 624 625 - ```jsx{10-15} 626 function Counter() { 627 const [delay, setDelay] = useState(1000); 628 const [count, setCount] = useState(0);
··· 30 31 Without further ado, here’s a counter that increments every second: 32 33 + ```jsx {6-9} 34 import React, { useState, useEffect, useRef } from 'react'; 35 36 function Counter() { ··· 128 129 So how would you do this with `setInterval` in a class? I ended up with this: 130 131 + ```jsx {7-26} 132 class Counter extends React.Component { 133 state = { 134 count: 0, ··· 179 180 <font size="50">🥁🥁🥁</font> 181 182 + ```jsx {5-8} 183 function Counter() { 184 let [count, setCount] = useState(0); 185 let [delay, setDelay] = useState(1000); ··· 208 209 Unlike the class version, there is no complexity gap for “upgrading” the `useInterval` Hook example to have a dynamically adjusted delay: 210 211 + ```jsx {4,9} 212 // Constant delay 213 useInterval(() => { 214 setCount(count + 1); ··· 226 227 What if I want to temporarily *pause* my interval? I can do this with state too: 228 229 + ```jsx {6} 230 const [delay, setDelay] = useState(1000); 231 const [isRunning, setIsRunning] = useState(true); 232 ··· 260 261 Now I want an interval that increments it every second. It’s a [side effect that needs cleanup](https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup) so I’m going to `useEffect()` and return the cleanup function: 262 263 + ```jsx {4-9} 264 function Counter() { 265 let [count, setCount] = useState(0); 266 ··· 304 305 You might know that `useEffect()` lets us [*opt out*](https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects) of re-applying effects. You can specify a dependency array as a second argument, and React will only re-run the effect if something in that array changes: 306 307 + ```jsx {3} 308 useEffect(() => { 309 document.title = `You clicked ${count} times`; 310 }, [count]); ··· 316 317 In the first attempt, our problem was that re-running the effects caused our timer to get cleared too early. We can try to fix it by never re-running them: 318 319 + ```jsx {9} 320 function Counter() { 321 let [count, setCount] = useState(0); 322 ··· 364 365 Hooks let us apply the same declarative approach to effects: 366 367 + ```jsx {4} 368 // Describes every interval state 369 useInterval(() => { 370 setCount(count + 1); ··· 420 421 `useRef()` returns a plain object with a mutable `current` property that’s shared between renders. We can save the *latest* interval callback into it: 422 423 + ```jsx {8} 424 function callback() { 425 // Can read fresh props, state, etc. 426 setCount(count + 1); ··· 434 435 And then we can read and call it from inside our interval: 436 437 + ```jsx {3,8} 438 useEffect(() => { 439 function tick() { 440 savedCallback.current(); ··· 449 450 Here’s a complete working solution: 451 452 + ```jsx {10,15} 453 function Counter() { 454 const [count, setCount] = useState(0); 455 const savedCallback = useRef(); ··· 487 488 Ideally, I just want to write this: 489 490 + ```jsx {4-6} 491 function Counter() { 492 const [count, setCount] = useState(0); 493 ··· 534 535 Now that the `delay` can change between renders, I need to declare it in the dependencies of my interval effect: 536 537 + ```jsx {8} 538 useEffect(() => { 539 function tick() { 540 savedCallback.current(); ··· 586 587 Say we want to be able to pause our interval by passing `null` as the `delay`: 588 589 + ```jsx {6} 590 const [delay, setDelay] = useState(1000); 591 const [isRunning, setIsRunning] = useState(true); 592 ··· 597 598 How do we implement this? The answer is: by not setting up an interval. 599 600 + ```jsx {6} 601 useEffect(() => { 602 function tick() { 603 savedCallback.current(); ··· 622 623 ![Counter that automatically speeds up](./counter_inception.gif) 624 625 + ```jsx {10-15} 626 function Counter() { 627 const [delay, setDelay] = useState(1000); 628 const [count, setCount] = useState(0);
+1 -1
public/my-wishlist-for-hot-reloading/index.md
··· 59 60 For a long time, it seemed to me that implementing reliable hot reloading for functions *alone* would encourage people to write convoluted code just to avoid using classes. But with [Hooks](https://reactjs.org/docs/hooks-intro.html), function components are fully featured so this is not a concern anymore. And this approach “just works” with Hooks: 61 62 - ```jsx{4} 63 // Reassigns the latest version 64 window.latest_Button = function(props) { 65 // Your actual code is moved here by a plugin
··· 59 60 For a long time, it seemed to me that implementing reliable hot reloading for functions *alone* would encourage people to write convoluted code just to avoid using classes. But with [Hooks](https://reactjs.org/docs/hooks-intro.html), function components are fully featured so this is not a concern anymore. And this approach “just works” with Hooks: 61 62 + ```jsx {4} 63 // Reassigns the latest version 64 window.latest_Button = function(props) { 65 // Your actual code is moved here by a plugin
+23 -23
public/react-as-a-ui-runtime/index.md
··· 134 135 React will look at the `reactElement.type` (in our example, `'button'`) and ask the React DOM renderer to create a host instance for it and set the properties: 136 137 - ```jsx{3,4} 138 // Somewhere in the ReactDOM renderer (simplified) 139 function createHostInstance(reactElement) { 140 let domNode = document.createElement(reactElement.type); ··· 145 146 In our example, effectively React will do this: 147 148 - ```jsx{1,2} 149 let domNode = document.createElement('button'); 150 domNode.className = 'blue'; 151 ··· 158 159 What happens if we call `ReactDOM.render()` twice with the same container? 160 161 - ```jsx{2,11} 162 ReactDOM.render( 163 <button className="blue" />, 164 document.getElementById('container') ··· 208 209 Here is an example with comments showing roughly what React does: 210 211 - ```jsx{9,10,16,26,27} 212 // let domNode = document.createElement('button'); 213 // domNode.className = 'blue'; 214 // domContainer.appendChild(domNode); ··· 250 251 Say we want to first show only an input, but later render a message before it: 252 253 - ```jsx{12} 254 // First render 255 ReactDOM.render( 256 <dialog> ··· 277 278 So effectively the update code executed by React would be like: 279 280 - ```jsx{1,2,8,9} 281 let oldInputNode = dialogNode.firstChild; 282 dialogNode.removeChild(oldInputNode); 283 ··· 312 313 This example doesn’t suffer from the problem we just described. It might be easier to see why if we use object notation instead of JSX. Look at the `dialog` child element tree: 314 315 - ```jsx{12-15} 316 function Form({ showMessage }) { 317 let message = null; 318 if (showMessage) { ··· 392 393 **This is why React nags you to specify a special property called `key` every time you include an array of elements in your output:** 394 395 - ```jsx{5} 396 function ShoppingList({ list }) { 397 return ( 398 <form> ··· 454 455 However, *local mutation* is absolutely fine: 456 457 - ```jsx{2,5} 458 function FriendList({ friends }) { 459 let items = []; 460 for (let i = 0; i < friends.length; i++) { ··· 602 603 Consider this component putting `<Comments>` inside a `<Page>`: 604 605 - ```jsx{11} 606 function Story({ currentUser }) { 607 // return { 608 // type: Page, ··· 621 622 The `Page` component can render the children given to it inside some `Layout`: 623 624 - ```jsx{4} 625 function Page({ user, children }) { 626 return ( 627 <Layout> ··· 635 636 But what if it has an early exit condition? 637 638 - ```jsx{2-4} 639 function Page({ user, children }) { 640 if (!user.isLoggedIn) { 641 return <h1>Please log in</h1>; ··· 650 651 If we called `Comments()` as a function, it would execute immediately regardless of whether `Page` wants to render them or not: 652 653 - ```jsx{4,8} 654 // { 655 // type: Page, 656 // props: { ··· 664 665 But if we pass a React element, we don’t execute `Comments` ourselves at all: 666 667 - ```jsx{4,8} 668 // { 669 // type: Page, 670 // props: { ··· 689 690 We call these features *Hooks*. For example, `useState` is a Hook. 691 692 - ```jsx{2,6,7} 693 function Example() { 694 const [count, setCount] = useState(0); 695 ··· 723 724 When trees get too deep or wide, you can tell React to [memoize](https://en.wikipedia.org/wiki/Memoization) a subtree and reuse previous render results during shallow equal prop changes: 725 726 - ```jsx{5} 727 function Row({ item }) { 728 // ... 729 } ··· 754 755 Several components may want to update state in response to the same event. This example is contrived but it illustrates a common pattern: 756 757 - ```jsx{4,14} 758 function Parent() { 759 let [count, setCount] = useState(0); 760 return ( ··· 779 780 If React immediately re-rendered components in response to `setState` calls, we’d end up rendering the child twice: 781 782 - ```jsx{4,8} 783 *** Entering React's browser click event handler *** 784 Child (onClick) 785 - setState ··· 916 917 In React, this is done by declaring an effect: 918 919 - ```jsx{4-6} 920 function Example() { 921 const [count, setCount] = useState(0); 922 ··· 952 953 Sometimes, re-running the effect on every render can be undesirable. You can tell React to [skip](https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects) applying an effect if certain variables didn’t change: 954 955 - ```jsx{3} 956 useEffect(() => { 957 document.title = `You clicked ${count} times`; 958 }, [count]); ··· 981 982 To solve this, make sure that if you specify the dependency array, it includes **all** things that can change, including the functions: 983 984 - ```jsx{4} 985 useEffect(() => { 986 DataSource.addSubscription(handleChange); 987 return () => DataSource.removeSubscription(handleChange); ··· 996 997 Since Hooks like `useState` and `useEffect` are function calls, we can compose them into our own Hooks: 998 999 - ```jsx{2,8} 1000 function MyResponsiveComponent() { 1001 const width = useWindowWidth(); // Our custom Hook 1002 return ( ··· 1027 1028 If `use` *were* a syntax, it would make sense for it to be at the top level: 1029 1030 - ```jsx{3} 1031 // 😉 Note: not a real syntax 1032 component Example(props) { 1033 const [count, setCount] = use State(0);
··· 134 135 React will look at the `reactElement.type` (in our example, `'button'`) and ask the React DOM renderer to create a host instance for it and set the properties: 136 137 + ```jsx {3,4} 138 // Somewhere in the ReactDOM renderer (simplified) 139 function createHostInstance(reactElement) { 140 let domNode = document.createElement(reactElement.type); ··· 145 146 In our example, effectively React will do this: 147 148 + ```jsx {1,2} 149 let domNode = document.createElement('button'); 150 domNode.className = 'blue'; 151 ··· 158 159 What happens if we call `ReactDOM.render()` twice with the same container? 160 161 + ```jsx {2,11} 162 ReactDOM.render( 163 <button className="blue" />, 164 document.getElementById('container') ··· 208 209 Here is an example with comments showing roughly what React does: 210 211 + ```jsx {9,10,16,26,27} 212 // let domNode = document.createElement('button'); 213 // domNode.className = 'blue'; 214 // domContainer.appendChild(domNode); ··· 250 251 Say we want to first show only an input, but later render a message before it: 252 253 + ```jsx {12} 254 // First render 255 ReactDOM.render( 256 <dialog> ··· 277 278 So effectively the update code executed by React would be like: 279 280 + ```jsx {1,2,8,9} 281 let oldInputNode = dialogNode.firstChild; 282 dialogNode.removeChild(oldInputNode); 283 ··· 312 313 This example doesn’t suffer from the problem we just described. It might be easier to see why if we use object notation instead of JSX. Look at the `dialog` child element tree: 314 315 + ```jsx {12-15} 316 function Form({ showMessage }) { 317 let message = null; 318 if (showMessage) { ··· 392 393 **This is why React nags you to specify a special property called `key` every time you include an array of elements in your output:** 394 395 + ```jsx {5} 396 function ShoppingList({ list }) { 397 return ( 398 <form> ··· 454 455 However, *local mutation* is absolutely fine: 456 457 + ```jsx {2,5} 458 function FriendList({ friends }) { 459 let items = []; 460 for (let i = 0; i < friends.length; i++) { ··· 602 603 Consider this component putting `<Comments>` inside a `<Page>`: 604 605 + ```jsx {11} 606 function Story({ currentUser }) { 607 // return { 608 // type: Page, ··· 621 622 The `Page` component can render the children given to it inside some `Layout`: 623 624 + ```jsx {4} 625 function Page({ user, children }) { 626 return ( 627 <Layout> ··· 635 636 But what if it has an early exit condition? 637 638 + ```jsx {2-4} 639 function Page({ user, children }) { 640 if (!user.isLoggedIn) { 641 return <h1>Please log in</h1>; ··· 650 651 If we called `Comments()` as a function, it would execute immediately regardless of whether `Page` wants to render them or not: 652 653 + ```jsx {4,8} 654 // { 655 // type: Page, 656 // props: { ··· 664 665 But if we pass a React element, we don’t execute `Comments` ourselves at all: 666 667 + ```jsx {4,8} 668 // { 669 // type: Page, 670 // props: { ··· 689 690 We call these features *Hooks*. For example, `useState` is a Hook. 691 692 + ```jsx {2,6,7} 693 function Example() { 694 const [count, setCount] = useState(0); 695 ··· 723 724 When trees get too deep or wide, you can tell React to [memoize](https://en.wikipedia.org/wiki/Memoization) a subtree and reuse previous render results during shallow equal prop changes: 725 726 + ```jsx {5} 727 function Row({ item }) { 728 // ... 729 } ··· 754 755 Several components may want to update state in response to the same event. This example is contrived but it illustrates a common pattern: 756 757 + ```jsx {4,14} 758 function Parent() { 759 let [count, setCount] = useState(0); 760 return ( ··· 779 780 If React immediately re-rendered components in response to `setState` calls, we’d end up rendering the child twice: 781 782 + ```jsx {4,8} 783 *** Entering React's browser click event handler *** 784 Child (onClick) 785 - setState ··· 916 917 In React, this is done by declaring an effect: 918 919 + ```jsx {4-6} 920 function Example() { 921 const [count, setCount] = useState(0); 922 ··· 952 953 Sometimes, re-running the effect on every render can be undesirable. You can tell React to [skip](https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects) applying an effect if certain variables didn’t change: 954 955 + ```jsx {3} 956 useEffect(() => { 957 document.title = `You clicked ${count} times`; 958 }, [count]); ··· 981 982 To solve this, make sure that if you specify the dependency array, it includes **all** things that can change, including the functions: 983 984 + ```jsx {4} 985 useEffect(() => { 986 DataSource.addSubscription(handleChange); 987 return () => DataSource.removeSubscription(handleChange); ··· 996 997 Since Hooks like `useState` and `useEffect` are function calls, we can compose them into our own Hooks: 998 999 + ```jsx {2,8} 1000 function MyResponsiveComponent() { 1001 const width = useWindowWidth(); // Our custom Hook 1002 return ( ··· 1027 1028 If `use` *were* a syntax, it would make sense for it to be at the top level: 1029 1030 + ```jsx {3} 1031 // 😉 Note: not a real syntax 1032 component Example(props) { 1033 const [count, setCount] = use State(0);
+1 -1
public/the-bug-o-notation/index.md
··· 116 117 This code might not look too different. It’s even a bit more verbose. But it is *dramatically* simpler to debug because of this line: 118 119 - ```jsx{3} 120 function setState(nextState) { 121 // Clear all existing children 122 formStatus.innerHTML = '';
··· 116 117 This code might not look too different. It’s even a bit more verbose. But it is *dramatically* simpler to debug because of this line: 118 119 + ```jsx {3} 120 function setState(nextState) { 121 // Clear all existing children 122 formStatus.innerHTML = '';
+12 -12
public/why-do-hooks-rely-on-call-order/index.md
··· 35 36 There is one specific part that I’d like to focus on today. As you may recall, each Hook can be used in a component more than once. For example, we can declare [multiple state variables](https://reactjs.org/docs/hooks-state.html#tip-using-multiple-state-variables) by calling `useState()` repeatedly: 37 38 - ```jsx{2,3,4} 39 function Form() { 40 const [name, setName] = useState('Mary'); // State variable 1 41 const [surname, setSurname] = useState('Poppins'); // State variable 2 ··· 103 104 But the point of supporting multiple `useState()` calls is so that you can *extract* parts of stateful logic (state + effects) out of your components into custom Hooks which can *also* independently use local state and effects: 105 106 - ```jsx{6-7} 107 function Form() { 108 // Declare some state variables directly in component body 109 const [name, setName] = useState('Mary'); ··· 174 175 This proposal seems to work for extracting the `useWindowWidth()` Hook: 176 177 - ```jsx{4,11-17} 178 // ⚠️ This is NOT the React Hooks API 179 function Form() { 180 // ... ··· 196 197 But if we attempt to extract input handling, it would fail: 198 199 - ```jsx{4,5,19-29} 200 // ⚠️ This is NOT the React Hooks API 201 function Form() { 202 // ... ··· 251 252 Two custom Hooks like `useWindowWidth()` and `useNetworkStatus()` might want to use the same custom Hook like `useSubscription()` under the hood: 253 254 - ```jsx{12,23-27,32-42} 255 function StatusMessage() { 256 const width = useWindowWidth(); 257 const isOnline = useNetworkStatus(); ··· 330 331 One way could be to isolate state keys with closures. This would require you to “instantiate” custom Hooks and add a function wrapper around each of them: 332 333 - ```jsx{5,6} 334 /******************* 335 * useFormInput.js * 336 ******************/ ··· 354 355 Additionally, you have to repeat every custom Hook used in a component twice. Once in the top level scope (or inside a function scope if we’re writing a custom Hook), and once at the actual call site. This means you have to jump between the rendering and top-level declarations even for small changes: 356 357 - ```jsx{2,3,7,8} 358 // ⚠️ This is NOT the React Hooks API 359 const useNameFormInput = createUseFormInput(); 360 const useSurnameFormInput = createUseFormInput(); ··· 386 387 The idea is that we could *compose* keys every time we write a custom Hook. Something like this: 388 389 - ```jsx{4,5,16,17} 390 // ⚠️ This is NOT the React Hooks API 391 function Form() { 392 // ... ··· 423 424 What does this code mean exactly? 425 426 - ```jsx{3,4} 427 // ⚠️ This is NOT the React Hooks API 428 function Counter(props) { 429 if (props.isActive) { ··· 442 443 If conditional state gets preserved, what about an effect? 444 445 - ```jsx{5-8} 446 // ⚠️ This is NOT the React Hooks API 447 function Counter(props) { 448 if (props.isActive) { ··· 487 488 Here is a hypothetical example of a message recipient picker that shows whether the currently chosen friend is online: 489 490 - ```jsx{8,9} 491 const friendList = [ 492 { id: 1, name: 'Phoebe' }, 493 { id: 2, name: 'Rachel' }, ··· 532 533 This works because we can pass the return value of the `useState()` Hook to the `useFriendStatus()` Hook: 534 535 - ```jsx{2} 536 const [recipientID, setRecipientID] = useState(1); 537 const isRecipientOnline = useFriendStatus(recipientID); 538 ```
··· 35 36 There is one specific part that I’d like to focus on today. As you may recall, each Hook can be used in a component more than once. For example, we can declare [multiple state variables](https://reactjs.org/docs/hooks-state.html#tip-using-multiple-state-variables) by calling `useState()` repeatedly: 37 38 + ```jsx {2,3,4} 39 function Form() { 40 const [name, setName] = useState('Mary'); // State variable 1 41 const [surname, setSurname] = useState('Poppins'); // State variable 2 ··· 103 104 But the point of supporting multiple `useState()` calls is so that you can *extract* parts of stateful logic (state + effects) out of your components into custom Hooks which can *also* independently use local state and effects: 105 106 + ```jsx {6-7} 107 function Form() { 108 // Declare some state variables directly in component body 109 const [name, setName] = useState('Mary'); ··· 174 175 This proposal seems to work for extracting the `useWindowWidth()` Hook: 176 177 + ```jsx {4,11-17} 178 // ⚠️ This is NOT the React Hooks API 179 function Form() { 180 // ... ··· 196 197 But if we attempt to extract input handling, it would fail: 198 199 + ```jsx {4,5,19-29} 200 // ⚠️ This is NOT the React Hooks API 201 function Form() { 202 // ... ··· 251 252 Two custom Hooks like `useWindowWidth()` and `useNetworkStatus()` might want to use the same custom Hook like `useSubscription()` under the hood: 253 254 + ```jsx {12,23-27,32-42} 255 function StatusMessage() { 256 const width = useWindowWidth(); 257 const isOnline = useNetworkStatus(); ··· 330 331 One way could be to isolate state keys with closures. This would require you to “instantiate” custom Hooks and add a function wrapper around each of them: 332 333 + ```jsx {5,6} 334 /******************* 335 * useFormInput.js * 336 ******************/ ··· 354 355 Additionally, you have to repeat every custom Hook used in a component twice. Once in the top level scope (or inside a function scope if we’re writing a custom Hook), and once at the actual call site. This means you have to jump between the rendering and top-level declarations even for small changes: 356 357 + ```jsx {2,3,7,8} 358 // ⚠️ This is NOT the React Hooks API 359 const useNameFormInput = createUseFormInput(); 360 const useSurnameFormInput = createUseFormInput(); ··· 386 387 The idea is that we could *compose* keys every time we write a custom Hook. Something like this: 388 389 + ```jsx {4,5,16,17} 390 // ⚠️ This is NOT the React Hooks API 391 function Form() { 392 // ... ··· 423 424 What does this code mean exactly? 425 426 + ```jsx {3,4} 427 // ⚠️ This is NOT the React Hooks API 428 function Counter(props) { 429 if (props.isActive) { ··· 442 443 If conditional state gets preserved, what about an effect? 444 445 + ```jsx {5-8} 446 // ⚠️ This is NOT the React Hooks API 447 function Counter(props) { 448 if (props.isActive) { ··· 487 488 Here is a hypothetical example of a message recipient picker that shows whether the currently chosen friend is online: 489 490 + ```jsx {8,9} 491 const friendList = [ 492 { id: 1, name: 'Phoebe' }, 493 { id: 2, name: 'Rachel' }, ··· 532 533 This works because we can pass the return value of the `useState()` Hook to the `useFriendStatus()` Hook: 534 535 + ```jsx {2} 536 const [recipientID, setRecipientID] = useState(1); 537 const isRecipientOnline = useFriendStatus(recipientID); 538 ```
+3 -3
public/why-do-react-elements-have-typeof-property/index.md
··· 23 24 And that function gives you back an object. We call this object a React *element*. It tells React what to render next. Your components return a tree of them. 25 26 - ```jsx{9} 27 { 28 type: 'marquee', 29 props: { ··· 105 106 However, **if your server has a hole that lets the user store an arbitrary JSON object** while the client code expects a string, this could become a problem: 107 108 - ```jsx{2-10,15} 109 // Server could have a hole that lets user store JSON 110 let expectedTextButGotJSON = { 111 type: 'div', ··· 128 129 The fix in React 0.14 was to [tag every React element with a Symbol](https://github.com/facebook/react/pull/4832): 130 131 - ```jsx{9} 132 { 133 type: 'marquee', 134 props: {
··· 23 24 And that function gives you back an object. We call this object a React *element*. It tells React what to render next. Your components return a tree of them. 25 26 + ```jsx {9} 27 { 28 type: 'marquee', 29 props: { ··· 105 106 However, **if your server has a hole that lets the user store an arbitrary JSON object** while the client code expects a string, this could become a problem: 107 108 + ```jsx {2-10,15} 109 // Server could have a hole that lets user store JSON 110 let expectedTextButGotJSON = { 111 type: 'div', ··· 128 129 The fix in React 0.14 was to [tag every React element with a Symbol](https://github.com/facebook/react/pull/4832): 130 131 + ```jsx {9} 132 { 133 type: 'marquee', 134 props: {
+3 -3
public/why-do-we-write-super-props/index.md
··· 15 16 I wrote `super(props)` more times in my life than I’d like to know: 17 18 - ```jsx{3} 19 class Checkbox extends React.Component { 20 constructor(props) { 21 super(props); ··· 38 39 But let’s get back to this example using only ES2015 features: 40 41 - ```jsx{3} 42 class Checkbox extends React.Component { 43 constructor(props) { 44 super(props); ··· 145 146 **Probably not because it’s still confusing.** Sure, React would later assign `this.props` *after* your constructor has run. But `this.props` would still be undefined *between* the `super` call and the end of your constructor: 147 148 - ```jsx{14} 149 // Inside React 150 class Component { 151 constructor(props) {
··· 15 16 I wrote `super(props)` more times in my life than I’d like to know: 17 18 + ```jsx {3} 19 class Checkbox extends React.Component { 20 constructor(props) { 21 super(props); ··· 38 39 But let’s get back to this example using only ES2015 features: 40 41 + ```jsx {3} 42 class Checkbox extends React.Component { 43 constructor(props) { 44 super(props); ··· 145 146 **Probably not because it’s still confusing.** Sure, React would later assign `this.props` *after* your constructor has run. But `this.props` would still be undefined *between* the `super` call and the end of your constructor: 147 148 + ```jsx {14} 149 // Inside React 150 class Component { 151 constructor(props) {
+4 -4
public/why-isnt-x-a-hook/index.md
··· 61 62 Hooks are useful because you can pass values *between* Hooks: 63 64 - ```jsx{4,12,14} 65 function useWindowWidth() { 66 const [width, setWidth] = useState(window.innerWidth); 67 // ... ··· 108 109 `React.memo()` takes a component and returns a component: 110 111 - ```jsx{4} 112 function Button(props) { 113 // ... 114 } ··· 138 139 Let’s say we try to put `useBailout()` in two custom Hooks: 140 141 - ```jsx{4,5,19,20} 142 function useFriendStatus(friendID) { 143 const [isOnline, setIsOnline] = useState(null); 144 ··· 173 Now what happens if you use them both in the same component? 174 175 176 - ```jsx{2,3} 177 function ChatThread({ friendID, isTyping }) { 178 const width = useWindowWidth(); 179 const isOnline = useFriendStatus(friendID);
··· 61 62 Hooks are useful because you can pass values *between* Hooks: 63 64 + ```jsx {4,12,14} 65 function useWindowWidth() { 66 const [width, setWidth] = useState(window.innerWidth); 67 // ... ··· 108 109 `React.memo()` takes a component and returns a component: 110 111 + ```jsx {4} 112 function Button(props) { 113 // ... 114 } ··· 138 139 Let’s say we try to put `useBailout()` in two custom Hooks: 140 141 + ```jsx {4,5,19,20} 142 function useFriendStatus(friendID) { 143 const [isOnline, setIsOnline] = useState(null); 144 ··· 173 Now what happens if you use them both in the same component? 174 175 176 + ```jsx {2,3} 177 function ChatThread({ friendID, isTyping }) { 178 const width = useWindowWidth(); 179 const isOnline = useFriendStatus(friendID);
+24 -24
public/writing-resilient-components/index.md
··· 91 92 However, a common mistake when learning React is to copy props into state: 93 94 - ```jsx{3,6} 95 class Button extends React.Component { 96 state = { 97 color: this.props.color ··· 133 134 Computed values are another reason people sometimes attempt to copy props into state. For example, imagine that we determined the *button text* color based on an expensive computation with background `color` as an argument: 135 136 - ```jsx{3,9} 137 class Button extends React.Component { 138 state = { 139 textColor: slowlyCalculateTextColor(this.props.color) ··· 153 154 This component is buggy because it doesn’t recalculate `this.state.textColor` on the `color` prop change. The easiest fix would be to move the `textColor` calculation into the `render` method, and make this a `PureComponent`: 155 156 - ```jsx{1,3} 157 class Button extends React.PureComponent { 158 render() { 159 const textColor = slowlyCalculateTextColor(this.props.color); ··· 173 174 However, we might want to optimize it further. What if it’s the `children` prop that changed? It seems unfortunate to recalculate the `textColor` in that case. Our second attempt might be to invoke the calculation in `componentDidUpdate`: 175 176 - ```jsx{5-12} 177 class Button extends React.Component { 178 state = { 179 textColor: slowlyCalculateTextColor(this.props.color) ··· 207 208 With a class, you could use a [helper](https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#what-about-memoization) for memoization. However, Hooks take this a step further, giving you a built-in way to memoize expensive computations: 209 210 - ```jsx{2-5} 211 function Button({ color, children }) { 212 const textColor = useMemo( 213 () => slowlyCalculateTextColor(color), ··· 235 236 Consider this React component: 237 238 - ```jsx{5-7} 239 class SearchResults extends React.Component { 240 state = { 241 data: null ··· 258 259 A lot of React components are like this — but if we look a bit closer, we'll notice a bug. The `fetchResults` method uses the `query` prop for data fetching: 260 261 - ```jsx{2} 262 getFetchUrl() { 263 return 'http://myapi/results?query' + this.props.query; 264 } ··· 275 * Make sure that whenever those props change, we re-run the side effect. 276 - We can do this by adding the `componentDidUpdate` method. 277 278 - ```jsx{8-12,18} 279 class SearchResults extends React.Component { 280 state = { 281 data: null ··· 305 306 However, it’s challenging to remember not to break it again. For example, we might add `currentPage` to the local state, and use it in `getFetchUrl`: 307 308 - ```jsx{4,21} 309 class SearchResults extends React.Component { 310 state = { 311 data: null, ··· 350 351 Let’s fix our component to handle updates to the `currentPage` state: 352 353 - ```jsx{11,24} 354 class SearchResults extends React.Component { 355 state = { 356 data: null, ··· 391 392 However, one *could* design an API that *can* be statically analyzed for consistency. The [React `useEffect` Hook](/a-complete-guide-to-useeffect/) is an example of such API: 393 394 - ```jsx{13-14,19} 395 function SearchResults({ query }) { 396 const [data, setData] = useState(null); 397 const [currentPage, setCurrentPage] = useState(0); ··· 442 443 **However, if you try to “optimize” a component by writing your own comparison, you may mistakenly forget to compare function props:** 444 445 - ```jsx{2-5,7} 446 class Button extends React.Component { 447 shouldComponentUpdate(prevProps) { 448 // 🔴 Doesn't compare this.props.onClick ··· 464 465 It is easy to miss this mistake at first because with classes, you’d usually pass a *method* down, and so it would have the same identity anyway: 466 467 - ```jsx{2-4,9-11} 468 class MyForm extends React.Component { 469 handleClick = () => { // ✅ Always the same function 470 // Do something ··· 484 485 So our optimization doesn’t break *immediately*. However, it will keep “seeing” the old `onClick` value if it changes over time but other props don’t: 486 487 - ```jsx{6,13-15} 488 class MyForm extends React.Component { 489 state = { 490 isEnabled: true ··· 513 514 This could get even more confusing if the function identity itself depends on something that could change over time, like `draft.content` in this example: 515 516 - ```jsx{6-7} 517 drafts.map(draft => 518 <Button 519 color='blue' ··· 533 534 I recommend to avoid manually implementing `shouldComponentUpdate` and to avoid specifying a custom comparison to `React.memo()`. The default shallow comparison in `React.memo` will respect changing function identity: 535 536 - ```jsx{11} 537 function Button({ onClick, color, children }) { 538 const textColor = slowlyCalculateTextColor(color); 539 return ( ··· 553 554 If you insist on a custom comparison, **make sure that you don’t skip functions:** 555 556 - ```jsx{5} 557 shouldComponentUpdate(prevProps) { 558 // ✅ Compares this.props.onClick 559 return ( ··· 586 587 How can one violate this principle? React doesn’t make it very easy — but you can do it by using the legacy `componentWillReceiveProps` lifecycle method: 588 589 - ```jsx{5-8} 590 class TextInput extends React.Component { 591 state = { 592 value: '' ··· 659 660 To stress-test your component, you can temporarily add this code to its parent: 661 662 - ```jsx{2} 663 componentDidMount() { 664 // Don't forget to remove this immediately! 665 setInterval(() => this.forceUpdate(), 100); ··· 674 675 This code should work, right? 676 677 - ```jsx{1-2} 678 // 🤔 Should prevent unnecessary re-renders... right? 679 class TextInput extends React.PureComponent { 680 state = { ··· 702 703 However, this gives us a false sense of security. **This component is still not resilient to _actual_ prop changes.** For example, if we added *another* often-changing prop, like an animated `style`, we would still “lose” the internal state: 704 705 - ```jsx{2} 706 <TextInput 707 style={{opacity: someValueFromState}} 708 value={ ··· 727 728 It’s easy to check for these problems. Just for fun, try to render your app twice: 729 730 - ```jsx{3,4} 731 ReactDOM.render( 732 <> 733 <MyApp /> ··· 743 744 An example of a problematic pattern I’ve written myself a few times is performing global state “cleanup” in `componentWillUnmount`: 745 746 - ```jsx{2-3} 747 componentWillUnmount() { 748 // Resets something in Redux store 749 this.props.resetForm(); ··· 752 753 Of course, if there are two such components on the page, unmounting one of them can break the other one. Resetting “global” state on *mount* is no better: 754 755 - ```jsx{2-3} 756 componentDidMount() { 757 // Resets something in Redux store 758 this.props.resetForm();
··· 91 92 However, a common mistake when learning React is to copy props into state: 93 94 + ```jsx {3,6} 95 class Button extends React.Component { 96 state = { 97 color: this.props.color ··· 133 134 Computed values are another reason people sometimes attempt to copy props into state. For example, imagine that we determined the *button text* color based on an expensive computation with background `color` as an argument: 135 136 + ```jsx {3,9} 137 class Button extends React.Component { 138 state = { 139 textColor: slowlyCalculateTextColor(this.props.color) ··· 153 154 This component is buggy because it doesn’t recalculate `this.state.textColor` on the `color` prop change. The easiest fix would be to move the `textColor` calculation into the `render` method, and make this a `PureComponent`: 155 156 + ```jsx {1,3} 157 class Button extends React.PureComponent { 158 render() { 159 const textColor = slowlyCalculateTextColor(this.props.color); ··· 173 174 However, we might want to optimize it further. What if it’s the `children` prop that changed? It seems unfortunate to recalculate the `textColor` in that case. Our second attempt might be to invoke the calculation in `componentDidUpdate`: 175 176 + ```jsx {5-12} 177 class Button extends React.Component { 178 state = { 179 textColor: slowlyCalculateTextColor(this.props.color) ··· 207 208 With a class, you could use a [helper](https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#what-about-memoization) for memoization. However, Hooks take this a step further, giving you a built-in way to memoize expensive computations: 209 210 + ```jsx {2-5} 211 function Button({ color, children }) { 212 const textColor = useMemo( 213 () => slowlyCalculateTextColor(color), ··· 235 236 Consider this React component: 237 238 + ```jsx {5-7} 239 class SearchResults extends React.Component { 240 state = { 241 data: null ··· 258 259 A lot of React components are like this — but if we look a bit closer, we'll notice a bug. The `fetchResults` method uses the `query` prop for data fetching: 260 261 + ```jsx {2} 262 getFetchUrl() { 263 return 'http://myapi/results?query' + this.props.query; 264 } ··· 275 * Make sure that whenever those props change, we re-run the side effect. 276 - We can do this by adding the `componentDidUpdate` method. 277 278 + ```jsx {8-12,18} 279 class SearchResults extends React.Component { 280 state = { 281 data: null ··· 305 306 However, it’s challenging to remember not to break it again. For example, we might add `currentPage` to the local state, and use it in `getFetchUrl`: 307 308 + ```jsx {4,21} 309 class SearchResults extends React.Component { 310 state = { 311 data: null, ··· 350 351 Let’s fix our component to handle updates to the `currentPage` state: 352 353 + ```jsx {11,24} 354 class SearchResults extends React.Component { 355 state = { 356 data: null, ··· 391 392 However, one *could* design an API that *can* be statically analyzed for consistency. The [React `useEffect` Hook](/a-complete-guide-to-useeffect/) is an example of such API: 393 394 + ```jsx {13-14,19} 395 function SearchResults({ query }) { 396 const [data, setData] = useState(null); 397 const [currentPage, setCurrentPage] = useState(0); ··· 442 443 **However, if you try to “optimize” a component by writing your own comparison, you may mistakenly forget to compare function props:** 444 445 + ```jsx {2-5,7} 446 class Button extends React.Component { 447 shouldComponentUpdate(prevProps) { 448 // 🔴 Doesn't compare this.props.onClick ··· 464 465 It is easy to miss this mistake at first because with classes, you’d usually pass a *method* down, and so it would have the same identity anyway: 466 467 + ```jsx {2-4,9-11} 468 class MyForm extends React.Component { 469 handleClick = () => { // ✅ Always the same function 470 // Do something ··· 484 485 So our optimization doesn’t break *immediately*. However, it will keep “seeing” the old `onClick` value if it changes over time but other props don’t: 486 487 + ```jsx {6,13-15} 488 class MyForm extends React.Component { 489 state = { 490 isEnabled: true ··· 513 514 This could get even more confusing if the function identity itself depends on something that could change over time, like `draft.content` in this example: 515 516 + ```jsx {6-7} 517 drafts.map(draft => 518 <Button 519 color='blue' ··· 533 534 I recommend to avoid manually implementing `shouldComponentUpdate` and to avoid specifying a custom comparison to `React.memo()`. The default shallow comparison in `React.memo` will respect changing function identity: 535 536 + ```jsx {11} 537 function Button({ onClick, color, children }) { 538 const textColor = slowlyCalculateTextColor(color); 539 return ( ··· 553 554 If you insist on a custom comparison, **make sure that you don’t skip functions:** 555 556 + ```jsx {5} 557 shouldComponentUpdate(prevProps) { 558 // ✅ Compares this.props.onClick 559 return ( ··· 586 587 How can one violate this principle? React doesn’t make it very easy — but you can do it by using the legacy `componentWillReceiveProps` lifecycle method: 588 589 + ```jsx {5-8} 590 class TextInput extends React.Component { 591 state = { 592 value: '' ··· 659 660 To stress-test your component, you can temporarily add this code to its parent: 661 662 + ```jsx {2} 663 componentDidMount() { 664 // Don't forget to remove this immediately! 665 setInterval(() => this.forceUpdate(), 100); ··· 674 675 This code should work, right? 676 677 + ```jsx {1-2} 678 // 🤔 Should prevent unnecessary re-renders... right? 679 class TextInput extends React.PureComponent { 680 state = { ··· 702 703 However, this gives us a false sense of security. **This component is still not resilient to _actual_ prop changes.** For example, if we added *another* often-changing prop, like an animated `style`, we would still “lose” the internal state: 704 705 + ```jsx {2} 706 <TextInput 707 style={{opacity: someValueFromState}} 708 value={ ··· 727 728 It’s easy to check for these problems. Just for fun, try to render your app twice: 729 730 + ```jsx {3,4} 731 ReactDOM.render( 732 <> 733 <MyApp /> ··· 743 744 An example of a problematic pattern I’ve written myself a few times is performing global state “cleanup” in `componentWillUnmount`: 745 746 + ```jsx {2-3} 747 componentWillUnmount() { 748 // Resets something in Redux store 749 this.props.resetForm(); ··· 752 753 Of course, if there are two such components on the page, unmounting one of them can break the other one. Resetting “global” state on *mount* is no better: 754 755 + ```jsx {2-3} 756 componentDidMount() { 757 // Resets something in Redux store 758 this.props.resetForm();