Skip to content

Commit bd858da

Browse files
committed
Review edits: more mutation info, "Summary" sections
1 parent adac8bb commit bd858da

14 files changed

+59
-22
lines changed

docs/tutorials/essentials/part-1-overview-concepts.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ Here's what that data flow looks like visually:
441441

442442
Redux does have a number of new terms and concepts to remember. As a reminder, here's what we just covered:
443443

444-
:::tip
444+
:::Summary
445445

446446
- **Redux is a library for managing global application state**
447447
- Redux is typically used with the React-Redux library for integrating Redux and React together

docs/tutorials/essentials/part-2-app-structure.md

+11-3
Original file line numberDiff line numberDiff line change
@@ -303,20 +303,28 @@ Earlier, we talked about "mutation" (modifying existing object/array values) and
303303
In Redux, **our reducers are _never_ allowed to mutate the original / current state values!**
304304

305305
```js
306-
// Illegal - don't do this in a normal reducer!
306+
// Illegal - don't do this in a normal reducer!
307307
state.value = 123
308308
```
309309

310310
:::
311311

312+
There are several reasons why you must not mutate state in Redux:
313+
314+
- It causes bugs, such as the UI not updating properly to show the latest values
315+
- It makes it harder to understand why and how the state has been updated
316+
- It makes it harder to write tests
317+
- It breaks the ability to use "time-travel debugging" correctly
318+
- It goes against the intended spirit and usage patterns for Redux
319+
312320
So if we can't change the originals, how do we return an updated state?
313321

314322
:::tip
315323

316324
**Reducers can only make _copies_ of the original values, and then they can mutate the copies.**
317325

318326
```js
319-
// This is safe, because we made a copy
327+
// This is safe, because we made a copy
320328
return {
321329
...state,
322330
value: 123
@@ -720,7 +728,7 @@ Now, any React components that call `useSelector` or `useDispatch` will be talki
720728

721729
Even though the counter example app is pretty small, it showed all the key pieces of a React + Redux app working together. Here's what we covered:
722730

723-
:::tip
731+
:::Summary
724732

725733
- **We can create a Redux store using the Redux Toolkit `configureStore` API**
726734
- `configureStore` accepts a `reducer` function as a named argument

docs/tutorials/essentials/part-3-data-flow.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ Notice that our `AddPostForm` component has some React `useState` hooks inside,
428428

429429
Let's recap what you've learned in this section:
430430

431-
:::tip
431+
:::Summary
432432

433433
- **Redux state is updated by "reducer functions"**:
434434
- Reducers always calculate a new state _immutably_, by copying existing state values and modifying the copies with the new data

docs/tutorials/essentials/part-4-using-data.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,7 @@ It's actually starting to look more useful and interesting!
819819
820820
We've covered a lot of information and concepts in this section. Let's recap the important things to remember:
821821
822-
:::tip
822+
:::Summary
823823
824824
- **Any React component can use data from the Redux store as needed**
825825
- Any component can read any data that is in the Redux store

docs/tutorials/essentials/part-5-async-logic.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ Here's what our app looks like now that we're fetching data from that fake API:
784784
785785
As a reminder, here's what we covered in this section:
786786

787-
:::tip
787+
:::Summary
788788

789789
- **You can write reusable "selector" functions to encapsulate reading values from the Redux state**
790790
- Selectors are functions that get the Redux `state` as an argument, and return some data

docs/tutorials/essentials/part-6-performance-normalization.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,7 @@ Congratulations, you've completed the Redux Essentials tutorial! Let's see what
978978
979979
Here's what we covered in this section:
980980

981-
:::tip
981+
:::Summary
982982

983983
- **Memoized selector functions can be used to optimize performance**
984984
- Redux Toolkit re-exports the `createSelector` function from Reselect, which generates memoized selectors

docs/tutorials/fundamentals/part-1-overview.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ The center of every Redux application is the **store**. A "store" is a container
131131

132132
A store is a JavaScript object with a few special functions and abilities that make it different than a plain global object:
133133

134-
- You cannot directly modify or change the state that is kept inside the Redux store
134+
- You must never directly modify or change the state that is kept inside the Redux store
135135
- Instead, the only way to cause an update to the state is to create a plain **action** object that describes "something that happened in the application", and then **dispatch** the action to the store to tell it what happened.
136136
- When an action is dispatched, the store runs the root **reducer** function, and lets it calculate the new state based on the old state and the action
137137
- Finally, the store notifies **subscribers** that the state has been updated so the UI can be updated with the new data.
@@ -307,7 +307,7 @@ That counter example was small, but it does show all the working pieces of a rea
307307

308308
With that in mind, let's review what we've learned so far:
309309

310-
:::tip
310+
:::Summary
311311

312312
- **Redux is a library for managing global application state**
313313
- Redux is typically used with the React-Redux library for integrating Redux and React together

docs/tutorials/fundamentals/part-2-concepts-data-flow.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ Here's what that data flow looks like visually:
357357

358358
## What You've Learned
359359

360-
:::tip
360+
:::Summary
361361

362362
- **Redux's intent can be summarized in three principles**
363363
- Global app state is kept in a single store

docs/tutorials/fundamentals/part-3-state-actions-reducers.md

+12-4
Original file line numberDiff line numberDiff line change
@@ -365,20 +365,28 @@ Earlier, we talked about "mutation" (modifying existing object/array values) and
365365
In Redux, **our reducers are _never_ allowed to mutate the original / current state values!**
366366

367367
```js
368-
// Illegal - don't do this in a normal reducer!
368+
// Illegal - don't do this in a normal reducer!
369369
state.value = 123
370370
```
371371

372372
:::
373373

374+
There are several reasons why you must not mutate state in Redux:
375+
376+
- It causes bugs, such as the UI not updating properly to show the latest values
377+
- It makes it harder to understand why and how the state has been updated
378+
- It makes it harder to write tests
379+
- It breaks the ability to use "time-travel debugging" correctly
380+
- It goes against the intended spirit and usage patterns for Redux
381+
374382
So if we can't change the originals, how do we return an updated state?
375383

376384
:::tip
377385

378386
**Reducers can only make _copies_ of the original values, and then they can mutate the copies.**
379387

380388
```js
381-
// This is safe, because we made a copy
389+
// This is safe, because we made a copy
382390
return {
383391
...state,
384392
value: 123
@@ -698,14 +706,14 @@ Here's the contents of our app so far:
698706
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
699707
></iframe>
700708
701-
:::tip
709+
:::Summary
702710

703711
- **Redux apps use plain JS objects, arrays, and primitives as the state values**
704712
- The root state value should be a plain JS object
705713
- The state should contain the smallest amount of data needed to make the app work
706714
- Classes, Promises, functions, and other non-plain values should _not_ go in the Redux state
707715
- Reducers must not create random values like `Math.random()` or `Date.now()`
708-
- It's okay to have other state values that are not in the Redux store
716+
- It's okay to have other state values that are not in the Redux store (like local component state) side-by side with Redux
709717
- **Actions are plain objects with a `type` field that describe what happened**
710718
- The `type` field should be a readable string, and is usually written as `'feature/eventName'`
711719
- Actions may contain other values, which are typically stored in the `action.payload` field

docs/tutorials/fundamentals/part-4-store.md

+23-2
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ Notice that our app did _not_ log anything from the last action. That's because
156156
We specified the behavior of our app before we even started writing the UI. That
157157
helps give us confidence that the app will work as intended.
158158

159-
:::tip
159+
:::info
160160

161161
If you want, you can now try writing tests for your reducers. Because they're [pure functions](../../understanding/thinking-in-redux/ThreePrinciples.md#changes-are-made-with-pure-functions), it should be straightforward to test them. Call them with an example `state` and `action`,
162162
take the result, and check to see if it matches what you expect:
@@ -218,6 +218,27 @@ As you can see, the actual logic here is fairly short:
218218
- The store dispatches one action on startup to initialize the reducers with their state
219219
- The store API is an object with `{dispatch, subscribe, getState}` inside
220220

221+
To emphasize one of those in particular: notice that `getState` just returns whatever the current `state` value is. That means that **by default, nothing prevents you from accidentally mutating the current state value!** This code will run without any errors, but it's incorrect:
222+
223+
```js
224+
const state = store.getState()
225+
// ❌ Don't do this - it mutates the current state!
226+
state.filters.status = 'Active'
227+
```
228+
229+
In other words:
230+
231+
- The Redux store doesn't make an extra copy of the `state` value when you call `getState()`. It's exactly the same reference that was returned from the root reducer function
232+
- The Redux store doesn't do anything else to prevent accidental mutations. It _is_ possible to mutate the state, either inside a reducer or outside the store, and you must always be careful to avoid mutations.
233+
234+
One common cause of accidental mutations is sorting arrays. [**Calling `array.sort()` actually mutates the existing array**](https://doesitmutate.xyz/sort/). If we called `const sortedTodos = state.todos.sort()`, we'd end up mutating the real store state unintentionally.
235+
236+
:::tip
237+
238+
In [Part 8: Modern Redux](./part-8-modern-redux.md), we'll see how Redux Toolkit helps avoid mutations in reducers, and detects and warns about accidental mutations outside of reducers.
239+
240+
:::
241+
221242
## Configuring the Store
222243

223244
We've already seen that we can pass `rootReducer` and `preloadedState` arguments to `createStore`. However, `createStore` can also take one more argument, which is used to customize the store's abilities and give it new powers.
@@ -585,7 +606,7 @@ Let's see how our example app looks now:
585606
586607
And as a reminder, here's what we covered in this section:
587608

588-
:::tip
609+
:::Summary
589610

590611
- **Redux apps always have a single store**
591612
- Stores are created with the Redux `createStore` API

docs/tutorials/fundamentals/part-5-ui-and-react.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ In this section, we'll add a User Interface for our todo app. We'll see how Redu
2525

2626
## Integrating Redux with a UI
2727

28-
Redux is a standalone JS library. As we've already seen, you can create and use a Redux store even if you don't have a user interface set up. This also means that **you can use Redux with any UI framework**. You can write Redux apps with React, Vue, Angular, Ember, jQuery, or vanilla JavaScript.
28+
Redux is a standalone JS library. As we've already seen, you can create and use a Redux store even if you don't have a user interface set up. This also means that **you can use Redux with any UI framework** (or even without _any_ UI framework), and use it on both client and server. You can write Redux apps with React, Vue, Angular, Ember, jQuery, or vanilla JavaScript.
2929

3030
That said, **Redux was specifically designed to work well with [React](https://reactjs.org)**. React lets you describe your UI as a function of your state, and Redux contains state and updates it in response to actions.
3131

@@ -553,7 +553,7 @@ Let's see how the app looks now, including the components and sections we skippe
553553
sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"
554554
></iframe>
555555
556-
:::tip
556+
:::Summary
557557
558558
- **Redux stores can be used with any UI layer**
559559
- UI code always subscribes to the store, gets the latest state, and redraws itself

docs/tutorials/fundamentals/part-6-async-logic.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ Here's what the current app looks like:
445445
sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"
446446
></iframe>
447447
448-
:::tip
448+
:::Summary
449449

450450
- **Redux middleware were designed to enable writing logic that has side effects**
451451
- "Side effects" are code that changes state/behavior outside a function, like AJAX calls, modifying function arguments, or generating random values

docs/tutorials/fundamentals/part-7-standard-patterns.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,7 @@ Here's how our app looks after it's been fully converted to use these patterns:
972972
sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"
973973
></iframe>
974974
975-
:::tip
975+
:::Summary
976976

977977
- **Action creator functions encapsulate preparing action objects and thunks**
978978
- Action creators can accept arguments and contain setup logic, and return the final action object or thunk function

docs/tutorials/fundamentals/part-8-modern-redux.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,7 @@ Let's take one final look at the completed todo application, including all the c
838838
839839
And we'll do a final recap of the key points you learned in this section:
840840

841-
:::tip
841+
:::Summary
842842

843843
- **Redux Toolkit (RTK) is the standard way to write Redux logic**
844844
- RTK includes APIs that simplify most Redux code

0 commit comments

Comments
 (0)