Skip to content

Commit c779d5b

Browse files
committed
part 6a
1 parent 4097915 commit c779d5b

File tree

2 files changed

+247
-276
lines changed

2 files changed

+247
-276
lines changed

src/content/6/en/part6a.md

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ lang: en
77

88
<div class="content">
99

10-
So far, we have followed the state management conventions recommended by React. We have placed the state and the functions for handling it in [higher level](https://react.dev/learn/sharing-state-between-components) of the component structure of the application. Quite often most of the app state and state altering functions reside directly in the root component. The state and its handler methods have then been passed to other components with props. This works up to a certain point, but when applications grow larger, state management becomes challenging.
10+
So far, we have followed the state management conventions recommended by React. We have placed the state and the functions for handling it in the [higher level](https://react.dev/learn/sharing-state-between-components) of the component structure of the application. Quite often most of the app state and state altering functions reside directly in the root component. The state and its handler methods have then been passed to other components with props. This works up to a certain point, but when applications grow larger, state management becomes challenging.
1111

1212
### Flux-architecture
1313

@@ -27,7 +27,7 @@ Flux offers a standard way for how and where the application's state is kept and
2727

2828
### Redux
2929

30-
Facebook has an implementation for Flux, but we will be using the [Redux](https://redux.js.org) - library. It works with the same principle but is a bit simpler. Facebook also uses Redux now instead of their original Flux.
30+
Facebook has an implementation for Flux, but we will be using the [Redux](https://redux.js.org) library. It works with the same principle but is a bit simpler. Facebook also uses Redux now instead of their original Flux.
3131

3232
We will get to know Redux by implementing a counter application yet again:
3333

@@ -39,11 +39,11 @@ Create a new Vite application and install </i>redux</i> with the command
3939
npm install redux
4040
```
4141

42-
As in Flux, in Redux the state is also stored in a [store](https://redux.js.org/basics/store).
42+
As in Flux, in Redux the state is also stored in a [store](https://redux.js.org/tutorials/essentials/part-1-overview-concepts#store).
4343

4444
The whole state of the application is stored in <i>one</i> JavaScript object in the store. Because our application only needs the value of the counter, we will save it straight to the store. If the state was more complicated, different things in the state would be saved as separate fields of the object.
4545

46-
The state of the store is changed with [actions](https://redux.js.org/basics/actions). Actions are objects, which have at least a field determining the <i>type</i> of the action.
46+
The state of the store is changed with [actions](https://redux.js.org/tutorials/essentials/part-1-overview-concepts#actions). Actions are objects, which have at least a field determining the <i>type</i> of the action.
4747
Our application needs for example the following action:
4848

4949
```js
@@ -54,7 +54,7 @@ Our application needs for example the following action:
5454

5555
If there is data involved with the action, other fields can be declared as needed. However, our counting app is so simple that the actions are fine with just the type field.
5656

57-
The impact of the action to the state of the application is defined using a [reducer](https://redux.js.org/basics/reducers). In practice, a reducer is a function that is given the current state and an action as parameters. It <i>returns</i> a new state.
57+
The impact of the action to the state of the application is defined using a [reducer](https://redux.js.org/tutorials/essentials/part-1-overview-concepts#reducers). In practice, a reducer is a function that is given the current state and an action as parameters. It <i>returns</i> a new state.
5858

5959
Let's now define a reducer for our application:
6060

@@ -95,7 +95,7 @@ const counterReducer = (state = 0, action) => {
9595
}
9696
```
9797

98-
Reducer is never supposed to be called directly from the application's code. Reducer is only given as a parameter to the _createStore_-function which creates the store:
98+
The reducer is never supposed to be called directly from the application's code. It is only given as a parameter to the _createStore_ function which creates the store:
9999

100100
```js
101101
// highlight-start
@@ -111,7 +111,7 @@ const store = createStore(counterReducer)
111111
// highlight-end
112112
```
113113

114-
The store now uses the reducer to handle <i>actions</i>, which are <i>dispatched</i> or 'sent' to the store with its [dispatch](https://redux.js.org/api/store#dispatchaction) method.
114+
The store now uses the reducer to handle <i>actions</i>, which are <i>dispatched</i> or 'sent' to the store with its [dispatch](https://redux.js.org/tutorials/essentials/part-1-overview-concepts#dispatch) method.
115115

116116
```js
117117
store.dispatch({ type: 'INCREMENT' })
@@ -141,9 +141,9 @@ would print the following to the console
141141
-1
142142
</pre>
143143

144-
because at first, the state of the store is 0. After three <i>INCREMENT</i>-actions the state is 3. In the end, after <i>ZERO</i> and <i>DECREMENT</i> actions, the state is -1.
144+
because at first, the state of the store is 0. After three <i>INCREMENT</i> actions the state is 3. In the end, after the <i>ZERO</i> and <i>DECREMENT</i> actions, the state is -1.
145145

146-
The third important method the store has is [subscribe](https://redux.js.org/api/store#subscribelistener), which is used to create callback functions the store calls whenever an action is dispatched to the store.
146+
The third important method that the store has is [subscribe](https://redux.js.org/api/store#subscribelistener), which is used to create callback functions that the store calls whenever an action is dispatched to the store.
147147

148148
If, for example, we would add the following function to subscribe, <i>every change in the store</i> would be printed to the console.
149149

@@ -242,13 +242,13 @@ store.subscribe(renderApp)
242242
There are a few notable things in the code.
243243
<i>App</i> renders the value of the counter by asking it from the store with the method _store.getState()_. The action handlers of the buttons <i>dispatch</i> the right actions to the store.
244244

245-
When the state in the store is changed, React is not able to automatically rerender the application. Thus we have registered a function _renderApp_, which renders the whole app, to listen for changes in the store with the _store.subscribe_ method. Note that we have to immediately call the _renderApp_ method. Without the call, the first rendering of the app would never happen.
245+
When the state in the store is changed, React is not able to automatically re-render the application. Thus we have registered a function _renderApp_, which renders the whole app, to listen for changes in the store with the _store.subscribe_ method. Note that we have to immediately call the _renderApp_ method. Without the call, the first rendering of the app would never happen.
246246

247247
### A note about the use of createStore
248248

249249
The most observant will notice that the name of the function createStore is overlined. If you move the mouse over the name, an explanation will appear
250250

251-
![vscode error showing createStore deprecated and to use configureStore](../../images/6/30new.png)
251+
![vscode error showing createStore deprecated, use configureStore instead](../../images/6/30new.png)
252252

253253
The full explanation is as follows
254254

@@ -264,7 +264,7 @@ The full explanation is as follows
264264
265265
So, instead of the function <i>createStore</i>, it is recommended to use the slightly more "advanced" function <i>configureStore</i>, and we will also use it when we have achieved the basic functionality of Redux.
266266

267-
Side note: <i>createStore</i> is defined as "deprecated", which usually means that the feature will be removed in some newer version of the library. The explanation above and the discussion of [this one](https://stackoverflow.com/questions/71944111/redux-createstore-is-deprecated-cannot-get-state-from-getstate-in-redux-ac) reveal that <i> createStore</i> will not be removed, and it has been given the status <i>deprecated</i>, perhaps with slightly incorrect reasons. So the function is not obsolete, but today there is a more preferable, new way to do almost the same thing.
267+
Side note: <i>createStore</i> is defined as "deprecated", which usually means that the feature will be removed in some newer version of the library. The explanation above and this [discussion](https://stackoverflow.com/questions/71944111/redux-createstore-is-deprecated-cannot-get-state-from-getstate-in-redux-ac) reveal that <i>createStore</i> will not be removed, and it has been given the status <i>deprecated</i>, perhaps with slightly incorrect reasons. So the function is not obsolete, but today there is a more preferable, new way to do almost the same thing.
268268

269269
### Redux-notes
270270

@@ -351,7 +351,7 @@ const noteReducer = (state = [], action) => {
351351

352352
The state is now an Array. <i>NEW\_NOTE</i>-type actions cause a new note to be added to the state with the [push](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) method.
353353

354-
The application seems to be working, but the reducer we have declared is bad. It breaks the [basic assumption](https://redux.js.org/tutorials/essentials/part-1-overview-concepts#reducers) of Redux reducer that reducers must be [pure functions](https://en.wikipedia.org/wiki/Pure_function).
354+
The application seems to be working, but the reducer we have declared is bad. It breaks the [basic assumption](https://redux.js.org/tutorials/essentials/part-1-overview-concepts#reducers) that reducers must be [pure functions](https://en.wikipedia.org/wiki/Pure_function).
355355

356356
Pure functions are such, that they <i>do not cause any side effects</i> and they must always return the same response when called with the same parameters.
357357

@@ -431,9 +431,8 @@ module.exports = {
431431
}
432432
```
433433

434-
435-
To make testing easier, we'll first move the reducer's code to its own module to file <i>src/reducers/noteReducer.js</i>. We'll also add the library [deep-freeze](https://www.npmjs.com/package/deep-freeze), which can be used to ensure that the reducer has been correctly defined as an immutable function.
436-
Let's install the library as a development dependency
434+
To make testing easier, we'll first move the reducer's code to its own module, to the file <i>src/reducers/noteReducer.js</i>. We'll also add the library [deep-freeze](https://www.npmjs.com/package/deep-freeze), which can be used to ensure that the reducer has been correctly defined as an immutable function.
435+
Let's install the library as a development dependency:
437436

438437
```js
439438
npm install --save-dev deep-freeze
@@ -574,7 +573,7 @@ state.map(note =>
574573

575574
Because we now have quite good tests for the reducer, we can refactor the code safely.
576575

577-
Adding a new note creates the state it returns with Array's _concat_ function. Let's take a look at how we can achieve the same by using the JavaScript [array spread](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator) -syntax:
576+
Adding a new note creates the state returned from the Array's _concat_ function. Let's take a look at how we can achieve the same by using the JavaScript [array spread](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator) syntax:
578577

579578
```js
580579
const noteReducer = (state = [], action) => {
@@ -633,7 +632,7 @@ console.log(rest) // prints [3, 4, 5, 6]
633632

634633
Let's make a simplified version of the unicafe exercise from part 1. Let's handle the state management with Redux.
635634

636-
You can take the project from this repository <https://github.com/fullstack-hy2020/unicafe-redux> for the base of your project.
635+
You can take the code from this repository <https://github.com/fullstack-hy2020/unicafe-redux> for the base of your project.
637636

638637
<i>Start by removing the git configuration of the cloned repository, and by installing dependencies</i>
639638

@@ -643,7 +642,7 @@ rm -rf .git
643642
npm install
644643
```
645644

646-
#### 6.1: unicafe revisited, step1
645+
#### 6.1: Unicafe Revisited, step 1
647646

648647
Before implementing the functionality of the UI, let's implement the functionality required by the store.
649648

@@ -728,15 +727,13 @@ describe('unicafe reducer', () => {
728727
**Implement the reducer and its tests.**
729728

730729
In the tests, make sure that the reducer is an <i>immutable function</i> with the <i>deep-freeze</i> library.
731-
Ensure that the provided first test passes, because Redux expects that the reducer returns a sensible original state when it is called so that the first parameter <i>state</i>, which represents the previous state, is
732-
<i>undefined</i>.
730+
Ensure that the provided first test passes, because Redux expects that the reducer returns the original state when it is called with a first parameter - which represents the previous <i>state</i> - with the value <i>undefined</i>.
733731

734732
Start by expanding the reducer so that both tests pass. Then add the rest of the tests, and finally the functionality that they are testing.
735733

736-
A good model for the reducer is the [redux-notes](/en/part6/flux_architecture_and_redux#pure-functions-immutable)
737-
example above.
734+
A good model for the reducer is the [redux-notes](/en/part6/flux_architecture_and_redux#pure-functions-immutable) example above.
738735

739-
#### 6.2: unicafe revisited, step2
736+
#### 6.2: Unicafe Revisited, step2
740737

741738
Now implement the actual functionality of the application.
742739

@@ -813,7 +810,7 @@ The implementation of both functionalities is straightforward. It is noteworthy
813810
814811
You can read more about uncontrolled forms [here](https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/).
815812

816-
The method handler for adding new notes is simple, it just dispatches the action for adding notes:
813+
The method for adding new notes is simple, it just dispatches the action for adding notes:
817814

818815
```js
819816
addNote = (event) => {
@@ -878,7 +875,7 @@ const toggleImportanceOf = (id) => {
878875
}
879876
```
880877

881-
Functions that create actions are called [action creators](https://redux.js.org/tutorials/fundamentals/part-7-standard-patterns#action-creators).
878+
Functions that create actions are called [action creators](https://redux.js.org/tutorials/essentials/part-1-overview-concepts#action-creators).
882879

883880
The <i>App</i> component does not have to know anything about the inner representation of the actions anymore, it just gets the right action by calling the creator function:
884881

@@ -905,7 +902,7 @@ const App = () => {
905902
Aside from the reducer, our application is in one file. This is of course not sensible, and we should separate <i>App</i> into its module.
906903

907904
Now the question is, how can the <i>App</i> access the store after the move? And more broadly, when a component is composed of many smaller components, there must be a way for all of the components to access the store.
908-
There are multiple ways to share the Redux store with components. First, we will look into the newest, and possibly the easiest way, which is using the [hooks](https://react-redux.js.org/api/hooks) API of the [react-redux](https://react-redux.js.org/) library.
905+
There are multiple ways to share the Redux store with the components. First, we will look into the newest, and possibly the easiest way, which is using the [hooks](https://react-redux.js.org/api/hooks) API of the [react-redux](https://react-redux.js.org/) library.
909906

910907
First, we install react-redux
911908

@@ -994,7 +991,7 @@ export const toggleImportanceOf = (id) => {
994991
Normally (not as defaults) exported functions can be imported with the curly brace syntax:
995992

996993
```js
997-
import { createNote } from './../reducers/noteReducer'
994+
import { createNote } from '../../reducers/noteReducer'
998995
```
999996

1000997
Code for the <i>App</i> component
@@ -1193,15 +1190,15 @@ const App = () => {
11931190

11941191
<i>Notes</i>, on the other hand, is a [container](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0) component, as it contains some application logic: it defines what the event handlers of the <i>Note</i> components do and coordinates the configuration of <i>presentational</i> components, that is, the <i>Note</i>s.
11951192

1196-
The code of the Redux application can be found on [GitHub](https://github.com/fullstack-hy2020/redux-notes/tree/part6-1), branch <i>part6-1</i>.
1193+
The code of the Redux application can be found on [GitHub](https://github.com/fullstack-hy2020/redux-notes/tree/part6-1), on the branch <i>part6-1</i>.
11971194

11981195
</div>
11991196

12001197
<div class="tasks">
12011198

12021199
### Exercises 6.3.-6.8.
12031200

1204-
Let's make a new version of the anecdote voting application from part 1. Take the project from this repository <https://github.com/fullstack-hy2020/redux-anecdotes> to base your solution on.
1201+
Let's make a new version of the anecdote voting application from part 1. Take the project from this repository <https://github.com/fullstack-hy2020/redux-anecdotes> as the base of your solution.
12051202

12061203
If you clone the project into an existing git repository, <i>remove the git configuration of the cloned application:</i>
12071204

@@ -1221,29 +1218,29 @@ After completing these exercises, your application should look like this:
12211218

12221219
![browser showing anecdotes and vote buttons](../../images/6/3.png)
12231220

1224-
#### 6.3: anecdotes, step1
1221+
#### 6.3: Anecdotes, step 1
12251222

12261223
Implement the functionality for voting anecdotes. The number of votes must be saved to a Redux store.
12271224

1228-
#### 6.4: anecdotes, step2
1225+
#### 6.4: Anecdotes, step 2
12291226

12301227
Implement the functionality for adding new anecdotes.
12311228

12321229
You can keep the form uncontrolled like we did [earlier](/en/part6/flux_architecture_and_redux#uncontrolled-form).
12331230

1234-
#### 6.5: anecdotes, step3
1231+
#### 6.5: Anecdotes, step 3
12351232

12361233
Make sure that the anecdotes are ordered by the number of votes.
12371234

1238-
#### 6.6: anecdotes, step4
1235+
#### 6.6: Anecdotes, step 4
12391236

12401237
If you haven't done so already, separate the creation of action-objects to [action creator](https://read.reduxbook.com/markdown/part1/04-action-creators.html)-functions and place them in the <i>src/reducers/anecdoteReducer.js</i> file, so do what we have been doing since the chapter [action creators](/en/part6/flux_architecture_and_redux#action-creators).
12411238

1242-
#### 6.7: anecdotes, step5
1239+
#### 6.7: Anecdotes, step 5
12431240

12441241
Separate the creation of new anecdotes into a component called <i>AnecdoteForm</i>. Move all logic for creating a new anecdote into this new component.
12451242

1246-
#### 6.8: anecdotes, step6
1243+
#### 6.8: Anecdotes, step 6
12471244

12481245
Separate the rendering of the anecdote list into a component called <i>AnecdoteList</i>. Move all logic related to voting for an anecdote to this new component.
12491246

0 commit comments

Comments
 (0)