-
Notifications
You must be signed in to change notification settings - Fork 76
/
02.md
118 lines (83 loc) Β· 4.73 KB
/
02.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# useEffect: persistent state
## π Your Notes
Elaborate on your learnings here in `src/exercise/02.md`
## Background
`React.useEffect` is a built-in hook that allows you to run some custom code
after React renders (and re-renders) your component to the DOM. It accepts a
callback function which React will call after the DOM has been updated:
```javascript
React.useEffect(() => {
// your side-effect code here.
// this is where you can make HTTP requests or interact with browser APIs.
})
```
Feel free to take a look at `src/examples/hook-flow.png` if you're interested in
the timing of when your functions are run. This will make more sense after
finishing the exercises/extra credit/instruction.
## Exercise
Production deploys:
- [Exercise](https://react-hooks.netlify.app/isolated/exercise/02.js)
- [Final](https://react-hooks.netlify.app/isolated/final/02.js)
In this exercise, we're going to enhance our `<Greeting />` component to get its
initial state value from localStorage (if available) and keep localStorage
updated as the `name` is updated.
## Extra Credit
### 1. π― lazy state initialization
[Production deploy](https://react-hooks.netlify.app/isolated/final/02.extra-1.js)
Right now, every time our component function is run, our function reads from
localStorage. This is problematic because it could be a performance bottleneck
(reading from localStorage can be slow). And what's more we only actually need
to know the value from localStorage the first time this component is rendered!
So the additional reads are wasted effort.
To avoid this problem, React's useState hook allows you to pass a function
instead of the actual value, and then it will only call that function to get the
state value when the component is rendered the first time. So you can go from
this: `React.useState(someExpensiveComputation())` To this:
`React.useState(() => someExpensiveComputation())`
And the `someExpensiveComputation` function will only be called when it's
needed!
Make the `React.useState` call use lazy initialization to avoid a performance
bottleneck of reading into localStorage on every render.
> Learn more about
> [lazy state initialization](https://kentcdodds.com/blog/use-state-lazy-initialization-and-function-updates)
### 2. π― effect dependencies
[Production deploy](https://react-hooks.netlify.app/isolated/final/02.extra-2.js)
The callback we're passing to `React.useEffect` is called after _every_ render
of our component (including re-renders). This is exactly what we want because we
want to make sure that the `name` is saved into localStorage whenever it
changes, but there are various reasons a component can be re-rendered (for
example, when a parent component in the application tree gets re-rendered).
Really, we _only_ want localStorage to get updated when the `name` state
actually changes. It doesn't need to re-run any other time. Luckily for us,
`React.useEffect` allows you to pass a second argument called the "dependency
array" which signals to React that your effect callback function should be
called when (and only when) those dependencies change. So we can use this to
avoid doing unnecessary work!
Add a dependencies array for `React.useEffect` to avoid the callback being
called too frequently.
### 3. π― custom hook
[Production deploy](https://react-hooks.netlify.app/isolated/final/02.extra-3.js)
The best part of hooks is that if you find a bit of logic inside your component
function that you think would be useful elsewhere, you can put that in another
function and call it from the components that need it (just like regular
JavaScript). These functions you create are called "custom hooks".
Create a custom hook called `useLocalStorageState` for reusability of all this
logic.
### 4. π― flexible localStorage hook
[Production deploy](https://react-hooks.netlify.app/isolated/final/02.extra-4.js)
Take your custom `useLocalStorageState` hook and make it generic enough to
support any data type (remember, you have to serialize objects to strings... use
`JSON.stringify` and `JSON.parse`). Go wild with this!
## Notes
If you'd like to learn more about when different hooks are called and the order
in which they're called, then open up `src/examples/hook-flow.png` and
`src/examples/hook-flow.js`. Play around with that a bit and hopefully that will
help solidify this for you. Note that understanding this isn't absolutely
necessary for you to understand hooks, but it _will_ help you in some situations
so it's useful to understand.
> PLEASE NOTE: there was a subtle change in the order of cleanup functions
> getting called in React 17:
> <https://github.com/kentcdodds/react-hooks/issues/90>
## π¦ Feedback
Fill out
[the feedback form](https://ws.kcd.im/?ws=React%20Hooks%20%F0%9F%8E%A3&e=02%3A%20useEffect%3A%20persistent%20state&em=).