diff --git a/exercises/06.use-effect-http-requests/01.problem/02.md b/exercises/06.use-effect-http-requests/01.problem/02.md deleted file mode 100644 index 64ad0ad81..000000000 --- a/exercises/06.use-effect-http-requests/01.problem/02.md +++ /dev/null @@ -1,169 +0,0 @@ -# Synchronizing Side-Effects - -## 📝 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. -}) -``` - -`useState` is for managing our react component state and `useEffect` is for -synchronizing the our react component state with the everything outside our -react components. - -For example, things outside our react components include: - -- Remote server requests -- Browser APIs like local storage/document title/media devices/etc. -- Integrations with non-react code - -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-next.netlify.app/isolated/exercise/02.tsx) -- [Final](https://react-hooks-next.netlify.app/isolated/final/02.tsx) - -In this exercise, we're going to enhance our `` component to get -its initial state value from localStorage (if available) and keep localStorage -updated as the `username` is updated. - -## Extra Credit - -### 1. 💯 lazy state initialization - -[Production deploy](https://react-hooks-next.netlify.app/isolated/final/02.extra-1.tsx) - -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-next.netlify.app/isolated/final/02.extra-2.tsx) - -Add this log right before calling `window.localStorage.setItem`: - -```tsx -console.log(`updating local storage with "${username}"`) -``` - -Then, refresh the page and without touching anything else, click the submit -button. You should notice that this is logged twice: -`updating local storage with ""`. That's once for the initial run, and again for -the `setTouched` state update that happens when we click the submit button. -We're updating local storage unnecessarily! - -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 `username` 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, or if -our own internal state gets updated, like the `showError` state). - -Really, we _only_ want localStorage to get updated when the `username` 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. After you add the dependency array, you'll notice the log -only is called once 😄 - -### 3. 💯 custom hook - -[Production deploy](https://react-hooks-next.netlify.app/isolated/final/02.extra-3.tsx) - -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. - -🦉 Note: you're in control of the arguments and return value of your custom -hook, there are no rules. Just like regular functions. Cool huh? - -💰 For my solution, the end result allows people to use it like this: - -```tsx -const [username, setUsername] = useLocalStorageState( - 'username', - initialUsername, -) -``` - -This allows people to swap between `React.useState` and `useLocalStorageState` -pretty easily. - -🦺 If you struggle on how to type the return value of your `useLocalStorage` -hook, check -[Wrapping React.useState with TypeScript](https://kentcdodds.com/blog/wrapping-react-use-state-with-type-script). - -### 4. 💯 flexible localStorage hook - -[Production deploy](https://react-hooks-next.netlify.app/isolated/final/02.extra-4.tsx) - -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`). Note: this one's a bit of a challenge, but -have fun with it! - -🦉 NOTE: So far, we've been saving the string as-is. Now we're making our custom -hook support any data type (number/boolean/etc). This means that we'll be -serializing it and that means that strings will be set to `"string value"` -rather than simply `string value`. So I recommend you clear your devtools local -storage value when you implement your changes (or even better, add support for -what to do when deserialization fails). - -## 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: -> - -## 🦉 Feedback - -Fill out -[the feedback form](https://ws.kcd.im/?ws=React%20Hooks%20%F0%9F%8E%A3&e=02%3A%20Synchronizing%20Side-Effects&em=).