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/part6.md
+1-2Lines changed: 1 addition & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,8 +8,7 @@ lang: en
8
8
9
9
So far, we have placed the application's state and state logic directly inside React components. When applications grow larger, state management should be moved outside React components. In this part, we will introduce the Redux library, which is currently the most popular solution for managing the state of React applications.
10
10
11
-
We'll learn about the lightweight version of Redux directly supported by React, namely the React context and useRedux hook, as well as the React Query library that simplifies the server state management.
12
-
11
+
We'll learn about the lightweight version of Redux directly supported by React, namely the React context and useReducer hook, as well as the React Query library that simplifies the server state management.
Copy file name to clipboardExpand all lines: src/content/6/en/part6b.md
+20-20Lines changed: 20 additions & 20 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -87,7 +87,7 @@ We decide to implement the filter functionality by storing <i>the value of the f
87
87
}
88
88
```
89
89
90
-
Only the array of notes is stored in the state of the current implementation of our application. In the new implementation, the state object has two properties, <i>notes</i> that contains the array of notes and <i>filter</i> that contains a string indicating which notes should be displayed to the user.
90
+
Only the array of notes was stored in the state of the previous implementation of our application. In the new implementation, the state object has two properties, <i>notes</i> that contains the array of notes and <i>filter</i> that contains a string indicating which notes should be displayed to the user.
91
91
92
92
### Combined reducers
93
93
@@ -113,7 +113,7 @@ The actions for changing the state of the filter look like this:
113
113
}
114
114
```
115
115
116
-
Let's also create a new _action creator_ function. We will write the code for the action creator in a new <i>src/reducers/filterReducer.js</i> module:
116
+
Let's also create a new _action creator_ function. We will write its code in a new <i>src/reducers/filterReducer.js</i> module:
117
117
118
118
```js
119
119
constfilterReducer= (state='ALL', action) => {
@@ -135,7 +135,6 @@ We can create the actual reducer for our application by combining the two existi
135
135
Let's define the combined reducer in the <i>main.jsx</i> file:
Based on the console output one might get the impression that every action gets duplicated:
216
215
217
-

216
+

218
217
219
-
Is there a bug in our code? No. The combined reducer works in such a way that every <i>action</i> gets handled in <i>every</i> part of the combined reducer. Typically only one reducer is interested in any given action, but there are situations where multiple reducers change their respective parts of the state based on the same action.
218
+
Is there a bug in our code? No. The combined reducer works in such a way that every <i>action</i> gets handled in <i>every</i> part of the combined reducer, or in other words, every reducer "listens" to all of the dispatched actions and does something with them if it has been instructed to do so. Typically only one reducer is interested in any given action, but there are situations where multiple reducers change their respective parts of the state based on the same action.
With the new component <i>App</i> can be simplified as follows:
307
+
With the new component, <i>App</i> can be simplified as follows:
309
308
310
309
```js
311
310
importNotesfrom'./components/Notes'
@@ -387,7 +386,7 @@ The current version of the application can be found on [GitHub](https://github.c
387
386
388
387
### Exercise 6.9
389
388
390
-
#### 6.9 Better anecdotes, step7
389
+
#### 6.9 Better Anecdotes, step 7
391
390
392
391
Implement filtering for the anecdotes that are displayed to the user.
393
392
@@ -433,7 +432,6 @@ npm install @reduxjs/toolkit
433
432
Next, open the <i>main.jsx</i> file which currently creates the Redux store. Instead of Redux's <em>createStore</em> function, let's create the store using Redux Toolkit's [configureStore](https://redux-toolkit.js.org/api/configureStore) function:
We already got rid of a few lines of code now that we don't need the <em>combineReducers</em> function to create the reducer for the store. We will soon see that the <em>configureStore</em> function has many additional benefits such as the effortless integration of development tools and many commonly used libraries without the need for additional configuration.
461
+
We already got rid of a few lines of code, now we don't need the <em>combineReducers</em> function to create the store's reducer. We will soon see that the <em>configureStore</em> function has many additional benefits such as the effortless integration of development tools and many commonly used libraries without the need for additional configuration.
464
462
465
463
Let's move on to refactoring the reducers, which brings forth the benefits of the Redux Toolkit. With Redux Toolkit, we can easily create reducer and related action creators using the [createSlice](https://redux-toolkit.js.org/api/createSlice) function. We can use the <em>createSlice</em> function to refactor the reducer and action creators in the <i>reducers/noteReducer.js</i> file in the following manner:
The <em>createSlice</em> function's <em>name</em> parameter defines the prefix which is used in the action's type values. For example, the <em>createNote</em> action defined later will have the type value of <em>notes/createNote</em>. It is a good practice to give the parameter a value which is unique among the reducers. This way there won't be unexpected collisions between the application's action type values. The <em>initialState</em> parameter defines the reducer's initial state. The <em>reducers</em> parameter takes the reducer itself as an object, of which functions handle state changes caused by certain actions. Note that the <em>action.payload</em> in the function contains the argument provided by calling the action creator:
517
+
The <em>createSlice</em> function's <em>name</em> parameter defines the prefix which is used in the action's type values. For example, the <em>createNote</em> action defined later will have the type value of <em>notes/createNote</em>. It is a good practice to give the parameter a value which is unique among the reducers. This way there won't be unexpected collisions between the application's action type values.
518
+
The <em>initialState</em> parameter defines the reducer's initial state.
519
+
The <em>reducers</em> parameter takes the reducer itself as an object, of which functions handle state changes caused by certain actions. Note that the <em>action.payload</em> in the function contains the argument provided by calling the action creator:
520
520
521
521
```js
522
522
dispatch(createNote('Redux Toolkit is awesome!'))
523
523
```
524
524
525
-
This dispatch call responds to dispatching the following object:
525
+
This dispatch call is equivalent to dispatching the following object:
526
526
527
527
```js
528
528
dispatch({ type:'notes/createNote', payload:'Redux Toolkit is awesome!' })
@@ -544,7 +544,7 @@ createNote(state, action) {
544
544
545
545
We are mutating <em>state</em> argument's array by calling the <em>push</em> method instead of returning a new instance of the array. What's this all about?
546
546
547
-
Redux Toolkit utilizes the [Immer](https://immerjs.github.io/immer/) library with reducers created by <em>createSlice</em> function, which makes it possible to mutate the <em>state</em> argument inside the reducer. Immer uses the mutated state to produce a new, immutable state and thus the state changes remain immutable. Note that <em>state</em> can be changed without "mutating" it, as we have done with the <em>toggleImportanceOf</em> action. In this case, the function <i>returns</i> the new state. Nevertheless mutating the state will often come in handy especially when a complex state needs to be updated.
547
+
Redux Toolkit utilizes the [Immer](https://immerjs.github.io/immer/) library with reducers created by <em>createSlice</em> function, which makes it possible to mutate the <em>state</em> argument inside the reducer. Immer uses the mutated state to produce a new, immutable state and thus the state changes remain immutable. Note that <em>state</em> can be changed without "mutating" it, as we have done with the <em>toggleImportanceOf</em> action. In this case, the function directly <i>returns</i> the new state. Nevertheless mutating the state will often come in handy especially when a complex state needs to be updated.
548
548
549
549
The <em>createSlice</em> function returns an object containing the reducer as well as the action creators defined by the <em>reducers</em> parameter. The reducer can be accessed by the <em>noteSlice.reducer</em> property, whereas the action creators by the <em>noteSlice.actions</em> property. We can produce the file's exports in the following way:
550
550
@@ -655,9 +655,9 @@ The following is printed to the console
655
655
656
656

657
657
658
-
The output is interesting but not very useful. This is about the previously mentioned Immer library used by the Redux Toolkit, which is now used internally to save the state of the Store.
658
+
The output is interesting but not very useful. This is about the previously mentioned Immer library used by the Redux Toolkit internally to save the state of the Store.
659
659
660
-
The status can be converted to a human-readable format, e.g. by converting it to a string and back to a JavaScript object as follows:
660
+
The status can be converted to a human-readable format, e.g. by converting it first to a string and then back to a JavaScript object as follows:
@@ -671,13 +671,13 @@ Console output is now human readable
671
671
672
672
[Redux DevTools](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd) is a Chrome addon that offers useful development tools for Redux. It can be used for example to inspect the Redux store's state and dispatch actions through the browser's console. When the store is created using Redux Toolkit's <em>configureStore</em> function, no additional configuration is needed for Redux DevTools to work.
673
673
674
-
Once the addon is installed, clicking the <i>Redux</i> tab in the browser's console should open the development tools:
674
+
Once the addon is installed, clicking the <i>Redux</i> tab in the browser's developer tools, the Redux DevTools should open:
675
675
676
676

677
677
678
678
You can inspect how dispatching a certain action changes the state by clicking the action:
679
679
680
-

680
+

681
681
682
682
It is also possible to dispatch actions to the store using the development tools:
683
683
@@ -693,19 +693,19 @@ You can find the code for our current application in its entirety in the <i>part
693
693
694
694
Let's continue working on the anecdote application using Redux that we started in exercise 6.3.
695
695
696
-
#### 6.10 Better anecdotes, step8
696
+
#### 6.10 Better Anecdotes, step 8
697
697
698
698
Install Redux Toolkit for the project. Move the Redux store creation into the file <i>store.js</i> and use Redux Toolkit's <em>configureStore</em> to create the store.
699
699
700
700
Change the definition of the <i>filter reducer and action creators</i> to use the Redux Toolkit's <em>createSlice</em> function.
701
701
702
702
Also, start using Redux DevTools to debug the application's state easier.
703
703
704
-
#### 6.11 Better anecdotes, step9
704
+
#### 6.11 Better Anecdotes, step 9
705
705
706
706
Change also the definition of the <i>anecdote reducer and action creators</i> to use the Redux Toolkit's <em>createSlice</em> function.
707
707
708
-
#### 6.12 Better anecdotes, step10
708
+
#### 6.12 Better Anecdotes, step 10
709
709
710
710
The application has a ready-made body for the <i>Notification</i> component:
711
711
@@ -750,7 +750,7 @@ You will have to make changes to the application's existing reducer. Create a se
750
750
751
751
The application does not have to use the <i>Notification</i> component intelligently at this point in the exercises. It is enough for the application to display the initial value set for the message in the <i>notificationReducer</i>.
752
752
753
-
#### 6.13 Better anecdotes, step11
753
+
#### 6.13 Better Anecdotes, step 11
754
754
755
755
Extend the application so that it uses the <i>Notification</i> component to display a message for five seconds when the user votes for an anecdote or creates a new anecdote:
Copy file name to clipboardExpand all lines: src/content/6/en/part6c.md
+8-8Lines changed: 8 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -329,21 +329,21 @@ The current state of the code for the application can be found on [GitHub](https
329
329
330
330
### Exercises 6.14.-6.15.
331
331
332
-
#### 6.14 Anecdotes and the backend, step1
332
+
#### 6.14 Anecdotes and the Backend, step 1
333
333
334
334
When the application launches, fetch the anecdotes from the backend implemented using json-server.
335
335
336
336
As the initial backend data, you can use, e.g. [this](https://github.com/fullstack-hy2020/misc/blob/master/anecdotes.json).
337
337
338
-
#### 6.15 Anecdotes and the backend, step2
338
+
#### 6.15 Anecdotes and the Backend, step 2
339
339
340
340
Modify the creation of new anecdotes, so that the anecdotes are stored in the backend.
341
341
342
342
</div>
343
343
344
344
<divclass="content">
345
345
346
-
### Asynchronous actions and Redux thunk
346
+
### Asynchronous actions and Redux Thunk
347
347
348
348
Our approach is quite good, but it is not great that the communication with the server happens inside the functions of the components. It would be better if the communication could be abstracted away from the components so that they don't have to do anything else but call the appropriate <i>action creator</i>. As an example, <i>App</i> would initialize the state of the application as follows:
349
349
@@ -376,7 +376,7 @@ const NewNote = () => {
376
376
}
377
377
```
378
378
379
-
In this implementation, both components would dispatch an action without the need to know about the communication between the server that happens behind the scenes. These kinds of <i>async actions</i> can be implemented using the [Redux Thunk](https://github.com/reduxjs/redux-thunk) library. The use of the library doesn't need any additional configuration or even installation when the Redux store is created using the Redux Toolkit's <em>configureStore</em> function.
379
+
In this implementation, both components would dispatch an action without the need to know about the communication with the server that happens behind the scenes. These kinds of <i>async actions</i> can be implemented using the [Redux Thunk](https://github.com/reduxjs/redux-thunk) library. The use of the library doesn't need any additional configuration or even installation when the Redux store is created using the Redux Toolkit's <em>configureStore</em> function.
380
380
381
381
With Redux Thunk it is possible to implement <i>action creators</i> which return a function instead of an object. The function receives Redux store's <em>dispatch</em> and <em>getState</em> methods as parameters. This allows for example implementations of asynchronous action creators, which first wait for the completion of a certain asynchronous operation and after that dispatch some action, which changes the store's state.
382
382
@@ -557,19 +557,19 @@ Redux Toolkit offers a multitude of tools to simplify asynchronous state managem
557
557
558
558
### Exercises 6.16.-6.19.
559
559
560
-
#### 6.16 Anecdotes and the backend, step3
560
+
#### 6.16 Anecdotes and the Backend, step 3
561
561
562
562
Modify the initialization of the Redux store to happen using asynchronous action creators, which are made possible by the Redux Thunk library.
563
563
564
-
#### 6.17 Anecdotes and the backend, step4
564
+
#### 6.17 Anecdotes and the Backend, step 4
565
565
566
566
Also modify the creation of a new anecdote to happen using asynchronous action creators, made possible by the Redux Thunk library.
567
567
568
-
#### 6.18 Anecdotes and the backend, step5
568
+
#### 6.18 Anecdotes and the Backend, step 5
569
569
570
570
Voting does not yet save changes to the backend. Fix the situation with the help of the Redux Thunk library.
571
571
572
-
#### 6.19 Anecdotes and the backend, step6
572
+
#### 6.19 Anecdotes and the Backend, step 6
573
573
574
574
The creation of notifications is still a bit tedious since one has to do two actions and use the _setTimeout_ function:
0 commit comments