This article shares how I create a simple ToDo application with FeathersJS on the server side and ReactJs on the Client. I will go into some main parts of how to install, and use the FeathersJS client with ReactJS, so the article will skip quite a lot of parts such as data validation, effects, …
Setting
Create folders for the project:
1 2 3 4 5 |
mkdir todo cd todo && mkdir server cd server feathers generate app |
Create service Tasks:
1 2 |
feathers generate service |
Edit src/models/tasks.model.js
:
1 2 3 4 5 6 7 8 |
<span class="token keyword">const</span> schema <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Schema</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> text <span class="token punctuation">:</span> <span class="token punctuation">{</span> type <span class="token punctuation">:</span> String <span class="token punctuation">,</span> required <span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> status <span class="token punctuation">:</span> <span class="token punctuation">{</span> type <span class="token punctuation">:</span> String <span class="token punctuation">,</span> <span class="token keyword">enum</span> <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token string">'unfinished'</span> <span class="token punctuation">,</span> <span class="token string">'finished'</span> <span class="token punctuation">,</span> <span class="token string">'removed'</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token keyword">default</span> <span class="token punctuation">:</span> <span class="token string">'unfinished'</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> user <span class="token punctuation">:</span> <span class="token punctuation">{</span> type <span class="token punctuation">:</span> String <span class="token punctuation">,</span> required <span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> ref <span class="token punctuation">:</span> <span class="token string">'users'</span> <span class="token punctuation">,</span> index <span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> timestamps <span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
That’s it then server
Next to the Client, in the todo folder:
1 2 3 4 |
npx create-react-app client cd client yarn add @feathersjs/feathers @feathersjs/rest-client @feathersjs/authentication-client |
Install Feathers:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span class="token comment">// src/feathers.js</span> <span class="token keyword">import</span> feathers <span class="token keyword">from</span> <span class="token string">'@feathersjs/feathers'</span> <span class="token punctuation">;</span> <span class="token keyword">import</span> rest <span class="token keyword">from</span> <span class="token string">'@feathersjs/rest-client'</span> <span class="token punctuation">;</span> <span class="token keyword">import</span> authentication <span class="token keyword">from</span> <span class="token string">'@feathersjs/authentication-client'</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">feathers</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> restClient <span class="token operator">=</span> <span class="token function">rest</span> <span class="token punctuation">(</span> <span class="token string">'http://localhost:3030'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">configure</span> <span class="token punctuation">(</span> restClient <span class="token punctuation">.</span> <span class="token function">fetch</span> <span class="token punctuation">(</span> window <span class="token punctuation">.</span> fetch <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> app <span class="token punctuation">.</span> <span class="token function">configure</span> <span class="token punctuation">(</span> <span class="token function">authentication</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> storageKey <span class="token punctuation">:</span> <span class="token string">'authentication'</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> app <span class="token punctuation">;</span> |
Done installing to be able to use Feathers on the client, now I can embark on React code
Sample interface
Write a Code
Install some additional libraries:
- react-router-dom
- material-ui
- moment
Login and register
Registration:
1 2 3 4 5 6 7 8 9 |
<span class="token keyword">const</span> handleSubmitForm <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> data <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">await</span> feathers <span class="token punctuation">.</span> <span class="token function">service</span> <span class="token punctuation">(</span> <span class="token string">'users'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">create</span> <span class="token punctuation">(</span> data <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">SignUpSuccess</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> <span class="token function-variable function">SignUpSuccess</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> history <span class="token punctuation">.</span> <span class="token function">push</span> <span class="token punctuation">(</span> <span class="token string">'/signin'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
The code below to handle the login:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<span class="token keyword">const</span> handleSubmitForm <span class="token operator">=</span> <span class="token keyword">async</span> data <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> feathers <span class="token punctuation">.</span> <span class="token function">authenticate</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> strategy <span class="token punctuation">:</span> <span class="token string">'local'</span> <span class="token punctuation">,</span> <span class="token operator">...</span> data <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">signInSuccess</span> <span class="token punctuation">(</span> response <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span> <span class="token function">alert</span> <span class="token punctuation">(</span> <span class="token string">'Sign In Failed!'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">setCurrentUser</span> <span class="token punctuation">(</span> undefined <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">signInSuccess</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> user <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setCurrentUser</span> <span class="token punctuation">(</span> user <span class="token punctuation">)</span> <span class="token punctuation">;</span> history <span class="token punctuation">.</span> <span class="token function">push</span> <span class="token punctuation">(</span> <span class="token string">'/'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> |
Log in when you have accessToken in localStorage:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<span class="token function">useEffect</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> reAuthenticate <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> feathers <span class="token punctuation">.</span> <span class="token function">reAuthenticate</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> response <span class="token operator">&&</span> response <span class="token punctuation">.</span> user <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setCurrentUser</span> <span class="token punctuation">(</span> response <span class="token punctuation">.</span> user <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> authenticate <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> accessToken <span class="token operator">=</span> <span class="token keyword">await</span> feathers <span class="token punctuation">.</span> authentication <span class="token punctuation">.</span> <span class="token function">getAccessToken</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> accessToken <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">await</span> <span class="token function">reAuthenticate</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">setLoading</span> <span class="token punctuation">(</span> <span class="token boolean">false</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token function">authenticate</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Put together a diagram for everyone to see:
Tasks
Get the whole task:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span class="token function">useEffect</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> loadTasks <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> feathers <span class="token punctuation">.</span> <span class="token function">service</span> <span class="token punctuation">(</span> <span class="token string">'tasks'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">find</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> query <span class="token punctuation">:</span> <span class="token punctuation">{</span> user <span class="token punctuation">:</span> user <span class="token punctuation">.</span> _id <span class="token punctuation">,</span> $sort <span class="token punctuation">:</span> <span class="token punctuation">{</span> status <span class="token punctuation">:</span> <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">,</span> updatedAt <span class="token punctuation">:</span> <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">setTasks</span> <span class="token punctuation">(</span> response <span class="token punctuation">.</span> data <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token function">loadTasks</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> task <span class="token punctuation">,</span> user <span class="token punctuation">.</span> _id <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
This code [task, user._id]
means that when the task changes, I will reload the entire task list, I use this method to get back the task list when adding, and edit the status of the task.
Add new task:
1 2 3 4 5 6 7 |
<span class="token keyword">const</span> addTask <span class="token operator">=</span> <span class="token keyword">async</span> data <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> feathers <span class="token punctuation">.</span> <span class="token function">service</span> <span class="token punctuation">(</span> <span class="token string">'tasks'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">create</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> user <span class="token punctuation">:</span> user <span class="token punctuation">.</span> _id <span class="token punctuation">,</span> <span class="token operator">...</span> data <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">setTask</span> <span class="token punctuation">(</span> response <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> |
Change state:
1 2 3 4 5 6 7 8 9 10 11 |
<span class="token keyword">const</span> <span class="token function-variable function">getTask</span> <span class="token operator">=</span> <span class="token punctuation">(</span> id <span class="token punctuation">,</span> tasks <span class="token punctuation">)</span> <span class="token operator">=></span> tasks <span class="token punctuation">.</span> <span class="token function">find</span> <span class="token punctuation">(</span> task <span class="token operator">=></span> id <span class="token operator">===</span> task <span class="token punctuation">.</span> _id <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> changeStatusTask <span class="token operator">=</span> <span class="token keyword">async</span> id <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> task <span class="token operator">=</span> <span class="token function">getTask</span> <span class="token punctuation">(</span> id <span class="token punctuation">,</span> tasks <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> status <span class="token operator">=</span> task <span class="token punctuation">.</span> status <span class="token operator">===</span> <span class="token string">'finished'</span> <span class="token operator">?</span> <span class="token string">'unfinished'</span> <span class="token punctuation">:</span> <span class="token string">'finished'</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> feathers <span class="token punctuation">.</span> <span class="token function">service</span> <span class="token punctuation">(</span> <span class="token string">'tasks'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">patch</span> <span class="token punctuation">(</span> id <span class="token punctuation">,</span> <span class="token punctuation">{</span> status <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">setTask</span> <span class="token punctuation">(</span> response <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> |
Result
Repo github: https://github.com/hungkieu/Feathers-React-Todo-App
I summarized the article with the main ideas as follows:
- Use the Feathers Client with ReactJS.
- Authenticate user.
- Add, edit, delete.
Thanks for reading my article