Skip to content

Commit a968762

Browse files
committed
6abc to use vite
1 parent 30eb1a5 commit a968762

File tree

8 files changed

+135
-126
lines changed

8 files changed

+135
-126
lines changed

src/content/6/en/part6a.md

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ We will get to know Redux by implementing a counter application yet again:
3333

3434
![browser counter application](../../images/6/1.png)
3535

36-
Create a new create-react-app-application and install </i>redux</i> with the command
36+
Create a new Vite application and install </i>redux</i> with the command
3737

3838
```bash
3939
npm install redux
@@ -175,7 +175,7 @@ would cause the following to be printed
175175
-1
176176
</pre>
177177

178-
The code of our counter application is the following. All of the code has been written in the same file (_index.js_), so <i>store</i> is directly available for the React code. We will get to know better ways to structure React/Redux code later.
178+
The code of our counter application is the following. All of the code has been written in the same file (_main.jsx_), so <i>store</i> is directly available for the React code. We will get to know better ways to structure React/Redux code later.
179179

180180
```js
181181
import React from 'react'
@@ -374,8 +374,55 @@ Let's expand our reducer so that it can handle the change of a note's importance
374374
}
375375
```
376376

377-
Since we do not have any code which uses this functionality yet, we are expanding the reducer in the 'test-driven' way.
378-
Let's start by creating a test for handling the action <i>NEW\_NOTE</i>.
377+
Since we do not have any code which uses this functionality yet, we are expanding the reducer in the 'test-driven' way. Let's start by creating a test for handling the action <i>NEW\_NOTE</i>.
378+
379+
We have to first configure the [Jest](https://jestjs.io/) testing library for the project. Let us install the following dependencies:
380+
381+
```js
382+
npm install --save-dev jest @babel/preset-env @babel/preset-react eslint-plugin-jest
383+
```
384+
385+
Next we'll create the file <i>.babelrc</i>, with the following content:
386+
387+
```json
388+
{
389+
"presets": [
390+
"@babel/preset-env",
391+
["@babel/preset-react", { "runtime": "automatic" }]
392+
]
393+
}
394+
```
395+
396+
Let us expand <i>package.json</i> with a script for running the tests:
397+
398+
```json
399+
{
400+
// ...
401+
"scripts": {
402+
"dev": "vite",
403+
"build": "vite build",
404+
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
405+
"preview": "vite preview",
406+
"test": "jest" // highlight-line
407+
},
408+
// ...
409+
}
410+
```
411+
412+
And finally, <i>.eslintrc.cjs</i> needs to be altered as follows:
413+
414+
```js
415+
module.exports = {
416+
root: true,
417+
env: {
418+
browser: true,
419+
es2020: true,
420+
"jest/globals": true // highlight-line
421+
},
422+
// ...
423+
}
424+
```
425+
379426

380427
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.
381428
Let's install the library as a development dependency
@@ -854,9 +901,9 @@ First, we install react-redux
854901
npm install react-redux
855902
```
856903

857-
Next, we move the _App_ component into its own file _App.js_. Let's see how this affects the rest of the application files.
904+
Next, we move the _App_ component into its own file _App.jsx_. Let's see how this affects the rest of the application files.
858905

859-
_index.js_ becomes:
906+
_main.jsx_ becomes:
860907

861908
```js
862909
import React from 'react'
@@ -1008,8 +1055,7 @@ const App = () => {
10081055
}
10091056
```
10101057

1011-
The <i>useDispatch</i> hook provides any React component access to the dispatch function of the Redux store defined in <i>index.js</i>.
1012-
This allows all components to make changes to the state of the Redux store.
1058+
The <i>useDispatch</i> hook provides any React component access to the dispatch function of the Redux store defined in <i>main.jsx</i>. This allows all components to make changes to the state of the Redux store.
10131059

10141060
The component can access the notes stored in the store with the [useSelector](https://react-redux.js.org/api/hooks#useselector)-hook of the react-redux library.
10151061

@@ -1078,7 +1124,7 @@ export default NewNote
10781124

10791125
Unlike in the React code we did without Redux, the event handler for changing the state of the app (which now lives in Redux) has been moved away from the <i>App</i> to a child component. The logic for changing the state in Redux is still neatly separated from the whole React part of the application.
10801126

1081-
We'll also separate the list of notes and displaying a single note into their own components (which will both be placed in the <i>Notes.js</i> file ):
1127+
We'll also separate the list of notes and displaying a single note into their own components (which will both be placed in the <i>Notes.jsx</i> file ):
10821128

10831129
```js
10841130
import { useDispatch, useSelector } from 'react-redux' // highlight-line

src/content/6/en/part6b.md

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

88
<div class="content">
99

10-
Let's continue our work with the simplified [redux version](/en/part6/flux_architecture_and_redux#redux-notes) of our notes application.
10+
Let's continue our work with the simplified [Redux version](/en/part6/flux_architecture_and_redux#redux-notes) of our notes application.
1111

1212
To ease our development, let's change our reducer so that the store gets initialized with a state that contains a couple of notes:
1313

@@ -132,7 +132,7 @@ export default filterReducer
132132

133133
We can create the actual reducer for our application by combining the two existing reducers with the [combineReducers](https://redux.js.org/api/combinereducers) function.
134134

135-
Let's define the combined reducer in the <i>index.js</i> file:
135+
Let's define the combined reducer in the <i>main.jsx</i> file:
136136

137137
```js
138138
import React from 'react'
@@ -188,7 +188,7 @@ const reducer = combineReducers({
188188

189189
The state of the store defined by the reducer above is an object with two properties: <i>notes</i> and <i>filter</i>. The value of the <i>notes</i> property is defined by the <i>noteReducer</i>, which does not have to deal with the other properties of the state. Likewise, the <i>filter</i> property is managed by the <i>filterReducer</i>.
190190

191-
Before we make more changes to the code, let's take a look at how different actions change the state of the store defined by the combined reducer. Let's add the following to the <i>index.js</i> file:
191+
Before we make more changes to the code, let's take a look at how different actions change the state of the store defined by the combined reducer. Let's add the following to the <i>main.jsx</i> file:
192192

193193
```js
194194
import { createNote } from './reducers/noteReducer'
@@ -220,7 +220,7 @@ Is there a bug in our code? No. The combined reducer works in such a way that ev
220220

221221
### Finishing the filters
222222

223-
Let's finish the application so that it uses the combined reducer. We start by changing the rendering of the application and hooking up the store to the application in the <i>index.js</i> file:
223+
Let's finish the application so that it uses the combined reducer. We start by changing the rendering of the application and hooking up the store to the application in the <i>main.jsx</i> file:
224224

225225
```js
226226
ReactDOM.createRoot(document.getElementById('root')).render(
@@ -232,7 +232,7 @@ ReactDOM.createRoot(document.getElementById('root')).render(
232232

233233
Next, let's fix a bug that is caused by the code expecting the application store to be an array of notes:
234234

235-
![browser TypeError: notes.map is not a function](../../images/6/7ea.png)
235+
![browser TypeError: notes.map is not a function](../../images/6/7v.png)
236236

237237
It's an easy fix. Because the notes are in the store's field <i>notes</i>, we only have to make a little change to the selector function:
238238

@@ -269,7 +269,7 @@ And now it returns only its field <i>notes</i>
269269
const notes = useSelector(state => state.notes)
270270
```
271271

272-
Let's extract the visibility filter into its own <i>src/components/VisibilityFilter.js</i> component:
272+
Let's extract the visibility filter into its own <i>src/components/VisibilityFilter.jsx</i> component:
273273

274274
```js
275275
import { filterChange } from '../reducers/filterReducer'
@@ -430,7 +430,7 @@ Let's start using Redux Toolkit in our application by refactoring the existing c
430430
npm install @reduxjs/toolkit
431431
```
432432
433-
Next, open the <i>index.js</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:
433+
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:
434434
435435
```js
436436
import React from 'react'

src/content/6/en/part6c.md

Lines changed: 7 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ The initial state of the database is stored in the file <i>db.json</i>, which is
2828
}
2929
```
3030

31-
We'll install json-server for the project...
31+
We'll install json-server for the project:
3232

3333
```js
3434
npm install json-server --save-dev
@@ -121,7 +121,7 @@ export const { createNote, toggleImportanceOf, appendNote } = noteSlice.actions
121121
export default noteSlice.reducer
122122
```
123123

124-
A quick way to initialize the notes state based on the data received from the server is to fetch the notes in the <i>index.js</i> file and dispatch an action using the <em>appendNote</em> action creator for each individual note object:
124+
A quick way to initialize the notes state based on the data received from the server is to fetch the notes in the <i>main.jsx</i> file and dispatch an action using the <em>appendNote</em> action creator for each individual note object:
125125

126126
```js
127127
// ...
@@ -194,7 +194,7 @@ export const { createNote, toggleImportanceOf, appendNote, setNotes } = noteSlic
194194
export default noteSlice.reducer
195195
```
196196

197-
Now, the code in the <i>index.js</i> file looks a lot better:
197+
Now, the code in the <i>main.jsx</i> file looks a lot better:
198198

199199
```js
200200
// ...
@@ -215,7 +215,7 @@ noteService.getAll().then(notes =>
215215

216216
> **NB:** Why didn't we use await in place of promises and event handlers (registered to _then_-methods)?
217217
>
218-
> Await only works inside <i>async</i> functions, and the code in <i>index.js</i> is not inside a function, so due to the simple nature of the operation, we'll abstain from using <i>async</i> this time.
218+
> Await only works inside <i>async</i> functions, and the code in <i>main.jsx</i> is not inside a function, so due to the simple nature of the operation, we'll abstain from using <i>async</i> this time.
219219
220220
We do, however, decide to move the initialization of the notes into the <i>App</i> component, and, as usual, when fetching data from a server, we'll use the <i>effect hook</i>.
221221

@@ -249,48 +249,6 @@ const App = () => {
249249
export default App
250250
```
251251

252-
Using the useEffect hook causes an eslint warning:
253-
254-
![vscode warning useEffect missing dispatch dependency](../../images/6/26ea.png)
255-
256-
We can get rid of it by doing the following:
257-
258-
```js
259-
const App = () => {
260-
const dispatch = useDispatch()
261-
useEffect(() => {
262-
noteService
263-
.getAll().then(notes => dispatch(setNotes(notes)))
264-
}, [dispatch]) // highlight-line
265-
266-
// ...
267-
}
268-
```
269-
270-
Now the variable <i>dispatch</i> we define in the _App_ component, which practically is the dispatch function of the redux store, has been added to the array useEffect receives as a parameter.
271-
**If** the value of the dispatch variable would change during runtime,
272-
the effect would be executed again. This however cannot happen in our application, so the warning is unnecessary.
273-
274-
Another way to get rid of the warning would be to disable ESlint on that line:
275-
276-
```js
277-
const App = () => {
278-
const dispatch = useDispatch()
279-
useEffect(() => {
280-
noteService
281-
.getAll().then(notes => dispatch(setNotes(notes)))
282-
// highlight-start
283-
}, []) // eslint-disable-line react-hooks/exhaustive-deps
284-
// highlight-end
285-
286-
// ...
287-
}
288-
```
289-
290-
Generally disabling ESlint when it throws a warning is not a good idea. Even though the ESlint rule in question has caused some [arguments](https://github.com/facebook/create-react-app/issues/6880), we will use the first solution.
291-
292-
More about the need to define the hooks dependencies in [the react documentation](https://reactjs.org/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies).
293-
294252
### Sending data to the backend
295253

296254
We can do the same thing when it comes to creating a new note. Let's expand the code communicating with the server as follows:
@@ -395,7 +353,7 @@ const App = () => {
395353

396354
useEffect(() => {
397355
dispatch(initializeNotes())
398-
}, [dispatch])
356+
}, [])
399357

400358
// ...
401359
}
@@ -458,7 +416,7 @@ const App = () => {
458416
// highlight-start
459417
useEffect(() => {
460418
dispatch(initializeNotes())
461-
}, [dispatch])
419+
}, [])
462420
// highlight-end
463421

464422
return (
@@ -555,7 +513,7 @@ const NewNote = () => {
555513
}
556514
```
557515

558-
Finally, let's clean up the <i>index.js</i> file a bit by moving the code related to the creation of the Redux store into its own, <i>store.js</i> file:
516+
Finally, let's clean up the <i>main.jsx</i> file a bit by moving the code related to the creation of the Redux store into its own, <i>store.js</i> file:
559517

560518
```js
561519
import { configureStore } from '@reduxjs/toolkit'

src/content/6/fi/osa6a.md

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,53 @@ Laajennetaan reduceria siten, että se osaa käsitellä muistiinpanon tärkeytee
373373

374374
Koska meillä ei ole vielä koodia joka käyttää ominaisuutta, laajennetaan reduceria testivetoisesti. Aloitetaan tekemällä testi actionin <i>NEW\_NOTE</i> käsittelylle.
375375

376+
Konfiguroidaan sovellukseen [Jest](https://jestjs.io/). Aloitetaan asentamalla joukko kirjastoja:
377+
378+
```js
379+
npm install --save-dev jest @babel/preset-env @babel/preset-react eslint-plugin-jest
380+
```
381+
382+
Luodaan tiedosto <i>.babelrc</i>, jolla on seuraava sisältö:
383+
384+
```json
385+
{
386+
"presets": [
387+
"@babel/preset-env",
388+
["@babel/preset-react", { "runtime": "automatic" }]
389+
]
390+
}
391+
```
392+
393+
Lisätään tiedostoon <i>package.json</i> testit suorittava skripti:
394+
395+
```json
396+
{
397+
// ...
398+
"scripts": {
399+
"dev": "vite",
400+
"build": "vite build",
401+
"lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
402+
"preview": "vite preview",
403+
"test": "jest" // highlight-line
404+
},
405+
// ...
406+
}
407+
```
408+
409+
Tiedostoon <i>.eslintrc.cjs</i> tulee myös pieni lisäys:
410+
411+
```js
412+
module.exports = {
413+
root: true,
414+
env: {
415+
browser: true,
416+
es2020: true,
417+
"jest/globals": true // highlight-line
418+
},
419+
// ...
420+
}
421+
```
422+
376423
Jotta testaus olisi helpompaa, siirretään reducerin koodi ensin omaan moduuliinsa tiedostoon <i>src/reducers/noteReducer.js</i>. Otetaan lisäksi käyttöön kirjasto [deep-freeze](https://www.npmjs.com/package/deep-freeze), jonka avulla voimme varmistaa, että reducer on määritelty oikeaoppisesti puhtaana funktiona. Asennetaan kirjasto kehitysaikaiseksi riippuvuudeksi:
377424

378425
```js
@@ -832,17 +879,17 @@ const App = () => {
832879
833880
Koko sovellus on toistaiseksi kirjoitettu yhteen tiedostoon minkä ansiosta joka puolelta sovellusta on päästy käsiksi Redux-storeen. Entä jos haluamme jakaa sovelluksen useisiin, omiin tiedostoihinsa sijoitettuihin komponentteihin?
834881
835-
Tapoja välittää Redux-store sovelluksen komponenteille on useita. Tutustutaan ensin ehkä uusimpaan ja helpoimpaan tapaan eli [react-redux](https://react-redux.js.org/)-kirjaston tarjoamaan [hooks](https://react-redux.js.org/api/hooks)-rajapintaan.
882+
Tapoja välittää Redux-store sovelluksen komponenteille on useita. Tutustutaan ensin ehkä uusimpaan ja helpoimpaan tapaan eli [React Redux](https://react-redux.js.org/)-kirjaston tarjoamaan [hooks](https://react-redux.js.org/api/hooks)-rajapintaan.
836883
837884
Asennetaan react-redux:
838885
839886
```bash
840887
npm install react-redux
841888
```
842889
843-
Eriytetään komponentti _App_ tiedostoon _App.js_. Tarkastellaan kuitenkin ensin mitä sovelluksen muihin tiedostoihin tulee.
890+
Eriytetään komponentti _App_ tiedostoon _App.jsx_. Tarkastellaan kuitenkin ensin mitä sovelluksen muihin tiedostoihin tulee.
844891
845-
Tiedosto _index.js_ näyttää seuraavalta:
892+
Tiedosto _main.jsx_ näyttää seuraavalta:
846893
847894
```js
848895
import React from 'react'
@@ -921,7 +968,7 @@ Normaalisti (eli ei defaultina) exportattujen funktioiden käyttöönotto tapaht
921968
import { createNote } from './../reducers/noteReducer'
922969
```
923970
924-
Tiedoston _App.js_ sisältö on seuraava:
971+
Tiedoston _App.jsx_ sisältö on seuraava:
925972
926973
```js
927974
import { createNote, toggleImportanceOf } from './reducers/noteReducer' // highlight-line
@@ -992,7 +1039,7 @@ const App = () => {
9921039
}
9931040
```
9941041
995-
React Redux ‑kirjaston tarjoama <i>useDispatch</i>-hook siis tarjoaa mille tahansa React-komponentille pääsyn tiedostossa <i>index.js</i> määritellyn Redux-storen dispatch-funktioon, jonka avulla komponentti pääsee tekemään muutoksia Redux-storen tilaan.
1042+
React Redux ‑kirjaston tarjoama <i>useDispatch</i>-hook siis tarjoaa mille tahansa React-komponentille pääsyn tiedostossa <i>main.jsx</i> määritellyn Redux-storen dispatch-funktioon, jonka avulla komponentti pääsee tekemään muutoksia Redux-storen tilaan.
9961043
9971044
Storeen talletettuihin muistiinpanoihin komponentti pääsee käsiksi React Redux ‑kirjaston [useSelector](https://react-redux.js.org/api/hooks#useselector)-hookin kautta:
9981045
@@ -1061,7 +1108,7 @@ export default NewNote
10611108
10621109
Toisin kuin aiemmin ilman Reduxia tekemässämme React-koodissa, sovelluksen tilaa (joka on nyt siis Reduxissa) muuttava tapahtumankäsittelijä on siirretty pois <i>App</i>-komponentista, alikomponentin vastuulle. Itse tilaa muuttava logiikka on kuitenkin siististi Reduxissa eristettynä koko sovelluksen React-osuudesta.
10631110
1064-
Eriytetään vielä muistiinpanojen lista ja yksittäisen muistiinpanon esittäminen omiksi komponenteikseen (jotka molemmat sijoitetaan tiedostoon <i>Notes.js</i>):
1111+
Eriytetään vielä muistiinpanojen lista ja yksittäisen muistiinpanon esittäminen omiksi komponenteikseen (jotka molemmat sijoitetaan tiedostoon <i>Notes.jsx</i>):
10651112
10661113
```js
10671114
import { useDispatch, useSelector } from 'react-redux' // highlight-line

0 commit comments

Comments
 (0)