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
Material of Part 11 has been moved to <astyle={linkStyle}href="https://courses.mooc.fi/org/uh-cs/courses/full-stack-open-continuous-integration">https://courses.mooc.fi/org/uh-cs/courses/full-stack-open-continuous-integration</a>
52
+
<b>Changes in part 7 (6th April 2026):</b>
53
+
<ulstyle={{marginTop: 6,paddingLeft: 20}}>
54
+
<li><i>React router, UI libraries and Styled components moved to part 5</i></li>
55
+
<li><i>Webpack replaced with esbuild</i></li>
56
+
<li><i>Error boundaries and keeping the frontend and backend in a single repository covered</i></li>
57
+
<li><i>Some of the hook exercises have changed</i></li>
58
+
<li><i>Two new exercises for the blog list</i></li>
59
+
</ul>
53
60
</div>
54
-
<divstyle={{marginBottom: 10}}>
55
-
The content and exercises are still same, there is a change how exercises are submitted.
61
+
<divstyle={{marginBottom: 10}}>
62
+
There may still be some minor changes coming to the blog list exercise set in the next few days.
56
63
</div>
57
64
<div>
58
-
The old content is still found <astyle={linkStyle}href="https://github.com/fullstack-hy2020/fullstack-hy2020.github.io/tree/7599b17c02b056fcad4f12d8708f0e07980b7564/src/content/11">here</a>.
65
+
The old content is still found <astyle={linkStyle}href="https://github.com/fullstack-hy2020/fullstack-hy2020.github.io/tree/7599b17c02b056fcad4f12d8708f0e07980b7564/src/content/7/en">here</a>.
Copy file name to clipboardExpand all lines: src/content/7/en/part7a.md
+93-81Lines changed: 93 additions & 81 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,9 +7,9 @@ lang: en
7
7
8
8
<divclass="content">
9
9
10
-
The exercises in this part of the course differ a bit from the ones before. As usual, there are some exercises related to the theory of the <i>this</i> chapter. The other chapters of this part do not have separate exercises.
10
+
The exercises in this part of the course differ a bit from the ones before. As usual, there are some exercises related to the theory of this chapter. The other chapters of this part do not have separate exercises.
11
11
12
-
The rest of the exercises in this part are found [here](/en/part7/exercises_extending_the_bloglist).
12
+
In addition, this part contains a larger exercise series that extends the BlogList application built in parts 4 and 5. Those exercises are found [here](/en/part7/exercises_extending_the_bloglist).
13
13
14
14
### React Hooks
15
15
@@ -588,13 +588,22 @@ The internet is starting to fill up with more and more helpful material related
588
588
589
589
<divclass="tasks">
590
590
591
-
### Exercises 7.1.-7.5.
591
+
### Exercises 7.1.-7.6.
592
592
593
-
#### 7.1: useField hook
593
+
Let's once again return to working with anecdotes. Use the app found in the repository https://github.com/fullstack-hy2020/routed-anecdotes as the starting point for the exercises.
594
+
595
+
If you clone the project into an existing git repository, remember to delete the git configuration of the cloned application:
596
+
597
+
cd routed-anecdotes // go first to directory of the cloned repository
598
+
rm -rf .git
599
+
The application starts the usual way, but first, you need to install its dependencies:
594
600
595
-
Implement a <i>useField</i> custom hook in the file <i>src/hooks/index.js</i>. The hook should manage the state of a single form input field and return an object with the following properties: <i>type</i>, <i>value</i>, and <i>onChange</i>.
601
+
npm install
602
+
npm run dev
596
603
597
-
One natural place to save the custom hooks of your application is in the <i>/src/hooks/index.js</i> file.
604
+
#### 7.1: useField hook
605
+
606
+
Copy the <i>useField</i> custom hook in the file <i>src/hooks/index.js</i>. The hook should manage the state of a single form input field and return an object with the following properties: <i>type</i>, <i>value</i>, and <i>onChange</i>.
598
607
599
608
If you use the [named export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#Description) instead of the default export:
600
609
@@ -633,13 +642,13 @@ const App = () => {
633
642
}
634
643
```
635
644
636
-
Create a simple form that uses the hook for at least two input fields and displays the current values below the form.
645
+
Use the hook in the anecdote creation form.
637
646
638
647
#### 7.2: useField with reset
639
648
640
649
Add a button to the form that clears all input fields:
641
650
642
-

651
+

643
652
644
653
Expand the <i>useField</i> hook so that it exposes a <i>reset</i> function for clearing the field value.
645
654
@@ -653,7 +662,7 @@ We will return to this warning in the next exercise.
653
662
654
663
If your solution did not cause a warning to appear in the console, you have already finished this exercise.
655
664
656
-
If you see the _Invalid value for prop \`reset\` on \<input\>tag_ warning in the console, make the necessary changes to get rid of it.
665
+
If you see the <i>Invalid value for prop \`reset\` on \<input\>tag</i> warning in the console, make the necessary changes to get rid of it.
657
666
658
667
The reason for this warning is that after making the changes to your application, the following expression:
659
668
@@ -686,108 +695,111 @@ One simple fix would be to not use the spread syntax and write all of the forms
686
695
687
696
If we were to do this, we would lose much of the benefit provided by the <i>useField</i> hook. Instead, come up with a solution that fixes the issue, but is still easy to use with the spread syntax.
688
697
689
-
#### 7.4: Country hook
698
+
#### 7.4: useAnecdotes, step1
690
699
691
-
Use the code from <https://github.com/fullstack-hy2020/country-hook> as your starting point.
700
+
The project has a JSON server already configured. YOu can start it with:
692
701
693
-
The application can be used to search for a country's details from the service in <https://studies.cs.helsinki.fi/restcountries/>. If a country is found, its details are displayed:
702
+
```bash
703
+
npm run server
704
+
```
694
705
695
-

706
+
This starts a JSON Server backend that exposes the anecdotes collection as a REST resource at <i>http://localhost:3001/anecdotes</i>.
696
707
697
-
If no country is found, a message is displayed to the user:
708
+
The existing <i>services/anecdotes.js</i> file contains the functions needed to communicate with the backend (except for the last exercise). Note that the service uses the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) instead of Axios for HTTP requests. If you are unfamiliar with Fetch, have a look at [part 6](/en/part6/complex_state_fetch_testing#fetch-api) before continuing.
698
709
699
-

700
710
701
-
The application is otherwise complete, but you have to implement a custom hook <i>useCountry</i> that fetches the details of the country whose name is given to the hook as a parameter. Use a <i>useEffect</i> hook inside <i>useCountry</i> for the HTTP request.
711
+
The typical pattern for fetching data from a server in React looks like this:
702
712
703
-
Note that in this exercise it is essential to use useEffect's [second parameter](https://react.dev/reference/react/useEffect#parameters) array to control when the effect function is executed.
713
+
```js
714
+
import { useState, useEffect } from'react'
715
+
importanecdoteServicefrom'./services/anecdotes'
704
716
705
-
#### 7.5: Ultimate Hooks
717
+
constApp= () => {
718
+
const [anecdotes, setAnecdotes] =useState([])
706
719
707
-
The code of the application responsible for communicating with the backend of the note application of the previous parts looks like this:
Implement a custom hook <i>useAnecdotes</i> that encapsulates this server communication. For this exercise it is enough for the hook to fetch all anecdotes Adding new ones can be handled in the next exercise.
We notice that the code is in no way specific to the fact that our application deals with notes. Excluding the value of the _baseUrl_ variable, the same code could be reused in the blog post application for dealing with the communication with the backend.
760
+
**A hint:** it was previously mentioned that
742
761
743
-
Extract the code for communicating with the backend into its own _useResource_ hook. It is sufficient to implement fetching all resources and creating a new resource.
762
+
> A helpful way to think about it (that is, how a hook works): imagine copy-pasting all the code from inside your custom hook directly into the component.
744
763
745
-
You can do the exercise in the project found in the <https://github.com/fullstack-hy2020/ultimate-hooks> repository. The <i>App</i> component for the project is the following:
764
+
So now you should kind of do the opposite: copy-paste the relevant code from component to the hook. This includes both hooks <i>useState</i> and <i>useEffect</i>.
765
+
766
+
#### 7.5: useAnecdotes, step2
767
+
768
+
Extend the <i>useAnecdotes</i> hook so that it also supports creating new anecdotes. The hook should expose an <i>addAnecdote</i> function that sends the new anecdote to the server and updates the local state.
Extend the <i>useAnecdotes</i> hook with a <i>deleteAnecdote</i> function that removes an anecdote from the server and updates the local state. Add a delete button next to each anecdote in the list.
Also refactor the application so that neither the anecdote data nor the hook functions are passed down as props. Instead, the components that need them should call <i>useAnecdotes</i> directly. This means <i>App</i> no longer needs to act as an intermediary passing data and callbacks through the component tree.
783
+
784
+
After the refactoring, <i>App</i> should look like this:
785
+
786
+
```js
787
+
constApp= () => {
788
+
return (
789
+
<Router>
790
+
<div>
791
+
<h1>Software anecdotes</h1>
792
+
<Menu />
793
+
<Routes>
794
+
<Route path="/" element={<AnecdoteList />} />
795
+
<Route path="/create" element={<CreateNew />} />
796
+
<Route path="/about" element={<About />} />
797
+
</Routes>
798
+
<Footer />
799
+
</div>
800
+
</Router>
783
801
)
784
802
}
785
803
```
786
804
787
-
The _useResource_ custom hook returns an array of two items just like the state hooks. The first item of the array contains all of the individual resources and the second item of the array is an object that can be used for manipulating the resource collection, like creating new ones.
788
-
789
-
If you implement the hook correctly, it can be used for both notes and persons (start the server with the _npm run server_ command at port 3005).
790
-
791
-

0 commit comments