-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
334c801
commit c6e32c8
Showing
38 changed files
with
644 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,10 @@ | ||
# useReducer | ||
|
||
👨💼 Our users want a counter component and it's working fine, but Kellie 🧝♂️ has | ||
said we can improve the implementation using `useReducer` (actually, | ||
`useReducer` is absolutely overkill for a counter component like ours, but we'll | ||
be using it to learn how to use it). | ||
|
||
The emoji will guide you through this! | ||
|
||
📜 [`useReducer` docs](https://react.dev/reference/react/useReducer). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
# useReducer | ||
|
||
👨💼 Great first step. Let's keep iterating. |
12 changes: 12 additions & 0 deletions
12
exercises/01.use-reducer/02.problem.previous-state/README.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,13 @@ | ||
# Previous State | ||
|
||
👨💼 We want to change things a bit to have this API: | ||
|
||
```tsx | ||
const [count, changeCount] = useReducer(countReducer, initialCount) | ||
const increment = () => changeCount(step) | ||
const decrement = () => changeCount(-step) | ||
``` | ||
|
||
How would you need to change your reducer to make this work? | ||
|
||
🦉 This step is just to show that you can pass anything as the action. |
3 changes: 3 additions & 0 deletions
3
exercises/01.use-reducer/02.solution.previous-state/README.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
# Previous State | ||
|
||
👨💼 Great, now you should have a good handle on how calling the `dispatch` | ||
function with an argument sends that argument to your reducer. You have control! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,35 @@ | ||
# State Object | ||
|
||
👨💼 Back in the day, we had `this.setState` from class components? We're going to | ||
make the state updater (`dispatch` function) behave in a similar way by changing | ||
our `state` to an object (`{count: 0}`) and then calling the state updater with | ||
an object which merges with the current state. | ||
|
||
So here's how I want things to look now: | ||
|
||
```tsx | ||
const [state, setState] = useReducer(countReducer, { | ||
count: initialCount, | ||
}) | ||
const { count } = state | ||
const increment = () => setState({ count: count + step }) | ||
const decrement = () => setState({ count: count - step }) | ||
``` | ||
|
||
How would you need to change the reducer to make this work? | ||
|
||
How would you make it support multiple state properties? For example: | ||
|
||
```tsx | ||
const [state, setState] = useReducer(countReducer, { | ||
count: initialCount, | ||
someOtherState: 'hello', | ||
}) | ||
const { count } = state | ||
const increment = () => setState({ count: count + step }) | ||
const decrement = () => setState({ count: count - step }) | ||
``` | ||
|
||
Calling `increment` or `decrement` in this case should only update the `count` | ||
property and leave the `someOtherState` property alone. So the `setState` | ||
function should merge the new state with the old state. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
# State Object | ||
|
||
👨💼 Great! Hopefully you're starting to get the hang of this API! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,17 @@ | ||
# Action Function | ||
|
||
👨💼 `this.setState` from class components can also accept a function. So let's | ||
add support for that with our simulated `setState` function. See if you can | ||
figure out how to make your reducer support both the object as in the last step | ||
as well as a function callback: | ||
|
||
```tsx | ||
const [state, setState] = useReducer(countReducer, { | ||
count: initialCount, | ||
}) | ||
const { count } = state | ||
const increment = () => | ||
setState(currentState => ({ count: currentState.count + step })) | ||
const decrement = () => | ||
setState(currentState => ({ count: currentState.count - step })) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
# Action Function | ||
|
||
👨💼 Great work! You're doing awesome making this as dynamic as possible. |
19 changes: 19 additions & 0 deletions
19
exercises/01.use-reducer/05.problem.traditional/README.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,20 @@ | ||
# Traditional Reducer | ||
|
||
👨💼 Now it's time to get to the actual convention for reducers in React apps. | ||
|
||
Update your reducer so I can do this: | ||
|
||
```javascript | ||
const [state, dispatch] = useReducer(countReducer, { | ||
count: initialCount, | ||
}) | ||
const { count } = state | ||
const increment = () => dispatch({ type: 'INCREMENT', step }) | ||
const decrement = () => dispatch({ type: 'DECREMENT', step }) | ||
``` | ||
|
||
The key here is that the logic for updating the state is now in the reducer, and | ||
the component is just dispatching actions. This actually gives us a bit of a | ||
declarative API for updating state, which is nice. The component is just saying | ||
what it wants to happen, and the reducer is the one that decides how to make it | ||
happen. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
# Traditional Reducer | ||
|
||
👨💼 Great work! This is how we typically use the `useReducer` API conventionally | ||
and it's kinda nice for complex state management. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,7 @@ | ||
# Real World | ||
|
||
👨💼 Let's try our hand at using `useReducer` for something a little more real. | ||
We'll be refactoring the `useState` out of our tic-tac-toe game to use | ||
`useReducer` instead. | ||
|
||
Good luck! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
# Real World | ||
|
||
👨💼 Great! The game functions the same, but the state changes are encapsulated in | ||
the reducer which makes it easier to manage and test. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Advanced State Management | ||
|
||
👨💼 Great work! You've now explored the `useReducer` API pretty well and you | ||
should feel comfortable using it going forward. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 6 additions & 0 deletions
6
exercises/02.state-optimization/01.problem.optimize/README.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
exercises/02.state-optimization/01.solution.optimize/README.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
# Optimize state updates | ||
|
||
👨💼 Great! It's nice to know that with a simple check we can avoid triggering an | ||
unnecessary state update and improve performance a bit. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# State Optimization | ||
|
||
👨💼 Great! Now you know how to prevent unnecessary state changes that trigger | ||
rerenders. Good work. | ||
|
||
🦉 Normally you don't want to add complexity to your code to improve performance | ||
unless you have measured before/after to make certain that the change is actually | ||
worth it. In this case, the performance improvement is likely to be negligible | ||
unless you have a very large number of state updates happening in a short period | ||
of time. But the added complexity is probably about as negligible as the | ||
performance improvement, so either way it's a wash. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,30 @@ | ||
# Hook Function | ||
|
||
👨💼 We now want to create a reusable `useSearchParams` function which will handle | ||
the search params for us generally so we can use that logic in other components. | ||
|
||
<callout-info> | ||
There's a much more complete version of this hook as a part of | ||
[react-router](https://reactrouter.com/en/main/hooks/use-search-params) which | ||
you'll likely want to use in a real application. This is just a simple | ||
example. | ||
</callout-info> | ||
|
||
So your job is to take the logic from the `App` component that relates to the | ||
search params and put it in a new function called `useSearchParams`, then you'll | ||
use that function in the `App` component. | ||
|
||
```tsx | ||
const [searchParams, setSearchParams] = useSearchParams() | ||
``` | ||
|
||
For the types of that tuple, you may find this article helpful: | ||
[Wrapping React.useState with TypeScript](https://kentcdodds.com/blog/wrapping-react-use-state-with-type-script) | ||
|
||
<callout-info class="aside"> | ||
There are actually not a lot of lines changed in this step of the exercise, | ||
but we're going to be bringing in `useCallback` in the next step so keep | ||
going! | ||
</callout-info> | ||
|
||
Good luck! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
# Hook Function | ||
|
||
👨💼 Great job! You've made a custom hook! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,9 @@ | ||
# useCallback | ||
|
||
👨💼 We only call the `setSearchParams` function inside event handlers, so we | ||
don't have any problems, but we're making a reusable hook and we want to make | ||
certain people don't have problems if they need to use it in a `useEffect` or | ||
other hook that requires a dependency array. | ||
|
||
So I want you to wrap our `setSearchParams` function in `useCallback` to memoize | ||
it and avoid issues with the dependency array. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
# useCallback | ||
|
||
👨💼 Great job! Now we have a pretty good reusable hook for anyone who wants to | ||
control the search params! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Custom Hooks | ||
|
||
👨💼 Great job! | ||
|
||
🦉 Remember, | ||
|
||
> [Custom hooks are functions that use other hooks.](https://twitter.com/kentcdodds/status/1763633880349987151) | ||
That's the only technical requirement. The `use` prefix is a useful convention, | ||
but they're just functions. |
Oops, something went wrong.