You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/content/6/en/part6a.md
+33-36Lines changed: 33 additions & 36 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,7 +7,7 @@ lang: en
7
7
8
8
<divclass="content">
9
9
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.
11
11
12
12
### Flux-architecture
13
13
@@ -27,7 +27,7 @@ Flux offers a standard way for how and where the application's state is kept and
27
27
28
28
### Redux
29
29
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.
31
31
32
32
We will get to know Redux by implementing a counter application yet again:
33
33
@@ -39,11 +39,11 @@ Create a new Vite application and install </i>redux</i> with the command
39
39
npm install redux
40
40
```
41
41
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).
43
43
44
44
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.
45
45
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.
47
47
Our application needs for example the following action:
48
48
49
49
```js
@@ -54,7 +54,7 @@ Our application needs for example the following action:
54
54
55
55
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.
56
56
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.
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:
99
99
100
100
```js
101
101
// highlight-start
@@ -111,7 +111,7 @@ const store = createStore(counterReducer)
111
111
// highlight-end
112
112
```
113
113
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.
115
115
116
116
```js
117
117
store.dispatch({ type:'INCREMENT' })
@@ -141,9 +141,9 @@ would print the following to the console
141
141
-1
142
142
</pre>
143
143
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.
145
145
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.
147
147
148
148
If, for example, we would add the following function to subscribe, <i>every change in the store</i> would be printed to the console.
149
149
@@ -242,13 +242,13 @@ store.subscribe(renderApp)
242
242
There are a few notable things in the code.
243
243
<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.
244
244
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.
246
246
247
247
### A note about the use of createStore
248
248
249
249
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
250
250
251
-

251
+

252
252
253
253
The full explanation is as follows
254
254
@@ -264,7 +264,7 @@ The full explanation is as follows
264
264
265
265
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.
266
266
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.
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.
353
353
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).
355
355
356
356
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.
357
357
@@ -431,9 +431,8 @@ module.exports = {
431
431
}
432
432
```
433
433
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:
437
436
438
437
```js
439
438
npm install --save-dev deep-freeze
@@ -574,7 +573,7 @@ state.map(note =>
574
573
575
574
Because we now have quite good tests for the reducer, we can refactor the code safely.
576
575
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:
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>.
733
731
734
732
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.
735
733
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.
738
735
739
-
#### 6.2: unicafe revisited, step2
736
+
#### 6.2: Unicafe Revisited, step2
740
737
741
738
Now implement the actual functionality of the application.
742
739
@@ -813,7 +810,7 @@ The implementation of both functionalities is straightforward. It is noteworthy
813
810
814
811
You can read more about uncontrolled forms [here](https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/).
815
812
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:
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).
882
879
883
880
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:
884
881
@@ -905,7 +902,7 @@ const App = () => {
905
902
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.
906
903
907
904
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.
<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.
1195
1192
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>.
1197
1194
1198
1195
</div>
1199
1196
1200
1197
<divclass="tasks">
1201
1198
1202
1199
### Exercises 6.3.-6.8.
1203
1200
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.
1205
1202
1206
1203
If you clone the project into an existing git repository, <i>remove the git configuration of the cloned application:</i>
1207
1204
@@ -1221,29 +1218,29 @@ After completing these exercises, your application should look like this:
1221
1218
1222
1219

1223
1220
1224
-
#### 6.3: anecdotes, step1
1221
+
#### 6.3: Anecdotes, step 1
1225
1222
1226
1223
Implement the functionality for voting anecdotes. The number of votes must be saved to a Redux store.
1227
1224
1228
-
#### 6.4: anecdotes, step2
1225
+
#### 6.4: Anecdotes, step 2
1229
1226
1230
1227
Implement the functionality for adding new anecdotes.
1231
1228
1232
1229
You can keep the form uncontrolled like we did [earlier](/en/part6/flux_architecture_and_redux#uncontrolled-form).
1233
1230
1234
-
#### 6.5: anecdotes, step3
1231
+
#### 6.5: Anecdotes, step 3
1235
1232
1236
1233
Make sure that the anecdotes are ordered by the number of votes.
1237
1234
1238
-
#### 6.6: anecdotes, step4
1235
+
#### 6.6: Anecdotes, step 4
1239
1236
1240
1237
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).
1241
1238
1242
-
#### 6.7: anecdotes, step5
1239
+
#### 6.7: Anecdotes, step 5
1243
1240
1244
1241
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.
1245
1242
1246
-
#### 6.8: anecdotes, step6
1243
+
#### 6.8: Anecdotes, step 6
1247
1244
1248
1245
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.
0 commit comments