Creating an upvote system with React and Socket.io 🥳 🔝
What is this article about?
Upvotes became a great way to understand what your visitors want. You can take websites like ProductHunt, and public roadmaps like Gleap, Upvoty, Prodcamp, have the ability to let user share their thoughts (in votes).
Even Reddit, one of the most popular social media lets people upvote or downvote your posts. We are going to build something similar with images!
In this article, you’ll learn how to create an upvoting application that allows users to upload images using Websockets and upvote their favorite photos. You’ll also learn how to send emails via EmailJS to notify users when their images gain a vote.
Why Socket.io (Websockets)?
Websockets allows us to use bi-directional communication with the server. It means that if we put in an upvote, we can inform the other user about the new upvote without refreshing the page or using long-polling.
Socket.io is a popular JavaScript library that allows us to create real-time, bi-directional communication between software applications and a Node.js server. It is optimised to process a large volume of data with minimal delay and provides better functionalities, such as fallback to HTTP long-polling or automatic reconnection.
Novu – the first open-source notification infrastructure
Just a quick background about us. Novu is the first open-source notification infrastructure. We basically help to manage all the product notifications. It can be In-App (the bell icon like you have in Facebook – Websockets), Emails, SMSs and so on.
I would be super happy if you could give us a star! And let me also know in the comments ❤️
https://github.com/novuhq/novu
How to create a real-time connection with React and Socket.io
Here we’ll set up the project environment for the image upvoting application. You will also learn how to add Socket.io to a React and Node.js application and connect both development servers for real-time communication via Socket.io.
Create the project folder containing two sub-folders named client and server.
1 2 3 4 |
<span class="nb">mkdir </span>upvote-app <span class="nb">cd </span>upvote-app <span class="nb">mkdir </span>client server |
Navigate into the client folder via your terminal and create a new React.js project.
1 2 3 |
<span class="nb">cd </span>client npx create-react-app ./ |
Install Socket.io client API, React Toastify, and React Router. React Router is a JavaScript library that enables us to navigate between pages in a React application, and React Toastify is used to display colourful notifications to the users.
1 2 |
npm <span class="nb">install </span>socket.io-client react-router-dom react-toastify |
Delete the redundant files such as the logo and the test files from the React app, and update the App.js file to display Hello World
as below.
1 2 3 4 |
<span class="kd">function</span> <span class="nx">App</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="p">(</span> <span class="p"><</span><span class="nt">div</span><span class="p">></span> <span class="p"><</span><span class="nt">p</span><span class="p">></span>Hello World!<span class="p"></</span><span class="nt">p</span><span class="p">></span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> <span class="p">);</span> <span class="p">}</span> <span class="k">export</span> <span class="k">default</span> <span class="nx">App</span><span class="p">;</span> |
Add the Socket.io client API to the React app as below:
1 2 3 4 5 |
<span class="k">import</span> <span class="p">{</span> <span class="nx">io</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">socket.io-client</span><span class="dl">"</span><span class="p">;</span> <span class="c1">//👇🏻 http://localhost:4000 is where the server host URL.</span> <span class="kd">const</span> <span class="nx">socket</span> <span class="o">=</span> <span class="nx">io</span><span class="p">.</span><span class="nx">connect</span><span class="p">(</span><span class="dl">"</span><span class="s2">http://localhost:4000</span><span class="dl">"</span><span class="p">);</span> <span class="kd">function</span> <span class="nx">App</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="p">(</span> <span class="p"><</span><span class="nt">div</span><span class="p">></span> <span class="p"><</span><span class="nt">p</span><span class="p">></span>Hello World!<span class="p"></</span><span class="nt">p</span><span class="p">></span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> <span class="p">);</span> <span class="p">}</span> <span class="k">export</span> <span class="k">default</span> <span class="nx">App</span><span class="p">;</span> |
Navigate into the server folder and create a package.json
file.
1 2 |
<span class="nb">cd </span>server & npm init <span class="nt">-y</span> |
Install Express.js, CORS, Nodemon, and Socket.io Server API.
1 2 |
npm <span class="nb">install </span>express cors nodemon socket.io react-icons |
Express.js is a fast, minimalist framework that provides several features for building web applications in Node.js. CORS is a Node.js package that allows communication between different domains.
Nodemon is a Node.js tool that automatically restarts the server after detecting file changes, and Socket.io allows us to configure a real-time connection on the server.
Create an index.js file – the entry point to the web server.
1 2 |
<span class="nb">touch </span>index.js |
Set up a Node.js server using Express.js. The code snippet below returns a JSON object when you visit the http://localhost:4000/api
in your browser.
1 2 3 4 5 6 7 8 |
<span class="c1">//👇🏻index.js</span> <span class="kd">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">express</span><span class="dl">"</span><span class="p">);</span> <span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span> <span class="kd">const</span> <span class="nx">PORT</span> <span class="o">=</span> <span class="mi">4000</span><span class="p">;</span> <span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">urlencoded</span><span class="p">({</span> <span class="na">extended</span><span class="p">:</span> <span class="kc">true</span> <span class="p">}));</span> <span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">json</span><span class="p">());</span> <span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">"</span><span class="s2">/api</span><span class="dl">"</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">({</span> <span class="na">message</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Hello world</span><span class="dl">"</span><span class="p">,</span> <span class="p">});</span> <span class="p">});</span> <span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="nx">PORT</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">`Server listening on </span><span class="p">${</span><span class="nx">PORT</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span> <span class="p">});</span> |
Import the HTTP and the CORS library to allow data transfer between the client and the server domains.
1 2 3 4 5 6 7 8 9 10 |
<span class="kd">const</span> <span class="nx">express</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">express</span><span class="dl">"</span><span class="p">);</span> <span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span> <span class="kd">const</span> <span class="nx">PORT</span> <span class="o">=</span> <span class="mi">4000</span><span class="p">;</span> <span class="c1">//👇🏻 New imports</span> <span class="kd">const</span> <span class="nx">http</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">http</span><span class="dl">"</span><span class="p">).</span><span class="nx">Server</span><span class="p">(</span><span class="nx">app</span><span class="p">);</span> <span class="kd">const</span> <span class="nx">cors</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">"</span><span class="s2">cors</span><span class="dl">"</span><span class="p">);</span> <span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">urlencoded</span><span class="p">({</span> <span class="na">extended</span><span class="p">:</span> <span class="kc">true</span> <span class="p">}));</span> <span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nx">json</span><span class="p">());</span> <span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">cors</span><span class="p">());</span> <span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">"</span><span class="s2">/api</span><span class="dl">"</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">res</span><span class="p">.</span><span class="nx">json</span><span class="p">({</span> <span class="na">message</span><span class="p">:</span> <span class="dl">"</span><span class="s2">Hello world</span><span class="dl">"</span><span class="p">,</span> <span class="p">});</span> <span class="p">});</span> <span class="nx">http</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="nx">PORT</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">`Server listening on </span><span class="p">${</span><span class="nx">PORT</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span> <span class="p">});</span> |
Next, add Socket.io to the project to create a real-time connection. Before the app.get()
block, copy the code below.
1 2 3 4 5 6 7 |
<span class="c1">//👇🏻 New imports</span> <span class="p">.....</span> <span class="kd">const</span> <span class="nx">socketIO</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">socket.io</span><span class="dl">'</span><span class="p">)(</span><span class="nx">http</span><span class="p">,</span> <span class="p">{</span> <span class="na">cors</span><span class="p">:</span> <span class="p">{</span> <span class="na">origin</span><span class="p">:</span> <span class="dl">"</span><span class="s2">http://localhost:3000</span><span class="dl">"</span> <span class="p">}</span> <span class="p">});</span> <span class="c1">//👇🏻 Add this before the app.get() block</span> <span class="nx">socketIO</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">connection</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">socket</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">`⚡: </span><span class="p">${</span><span class="nx">socket</span><span class="p">.</span><span class="nx">id</span><span class="p">}</span><span class="s2"> user just connected!`</span><span class="p">);</span> <span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="dl">'</span><span class="s1">disconnect</span><span class="dl">'</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">socket</span><span class="p">.</span><span class="nx">disconnect</span><span class="p">()</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">🔥: A user disconnected</span><span class="dl">'</span><span class="p">);</span> <span class="p">});</span> <span class="p">});</span> |
From the code snippet above, the socket.io("connection")
function establishes a connection with the React app, then creates a unique ID for each socket and logs the ID to the console whenever a user visits the web page.
When you refresh or close the web page, the socket fires the disconnect event showing that a user has disconnected from the socket.
Configure Nodemon by adding the start command to the list of scripts in the package.json
file. The code snippet below starts the server using Nodemon.
1 2 3 4 |
<span class="c1">//👇🏻 In server/package.json"</span> <span class="dl">"</span><span class="s2">scripts</span><span class="dl">"</span><span class="p">:</span> <span class="p">{</span> <span class="dl">"</span><span class="s2">test</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">echo </span><span class="se">"</span><span class="s2">Error: no test specified</span><span class="se">"</span><span class="s2"> && exit 1</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">start</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">nodemon index.js</span><span class="dl">"</span> <span class="p">}</span> |
You can now run the server with Nodemon by using the command below.
1 2 |
npm start |
Building the user interface
Here, we’ll create the user interface for the upvoting application to enable users to sign in, upload images, and upvote any picture of their choice.
There are two rules required when building the upvoting application:
- users can only vote once.
- users can not upvote their own images.
Later in the tutorial, I will guide you on how you can build such a efficient upvoting system.
Navigate into the client/src
folder and create a components folder containing the Login.js
, Register.js
, Photos.js
, UploadPhoto.js
, MyPhotos
, and SharePhoto.js
files.
1 2 3 4 5 |
<span class="nb">cd </span>client <span class="nb">mkdir </span>components <span class="nb">cd </span>components <span class="nb">touch </span>Login.js Register.js Photos.js UploadPhoto.js MyPhoto.js SharePhoto.js |
From the code snippet above:
- The
Login
component is the application’s home page. It prompts users to sign in to the application. - The
Register
component enables new users to create an account before they can sign in to the application. - The
Photos
component is the home page displayed to the users after authentication. Users can view all the available images on this page and upvote them. - The
UploadPhoto
is only visible to authenticated users and allows users to upload images to the list of photos on the web application. - The
MyPhoto
page allows users to view only their uploaded images and share their profile links with friends. - The
SharePhoto
component is a dynamic route that shows all the images uploaded by a user.
Update the App.js
file to render the newly created components on different routes via React Router as below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react</span><span class="dl">"</span><span class="p">;</span> <span class="c1">//👇🏻 React Router configuration & routes</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">BrowserRouter</span><span class="p">,</span> <span class="nx">Routes</span><span class="p">,</span> <span class="nx">Route</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react-router-dom</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="nx">Photos</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./components/Photos</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="nx">Login</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./components/Login</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="nx">Register</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./components/Register</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="nx">UploadPhoto</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./components/UploadPhoto</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="nx">MyPhotos</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./components/MyPhotos</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="nx">SharePhoto</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./components/SharePhoto</span><span class="dl">"</span><span class="p">;</span> <span class="c1">//👇🏻 React Toastify configuration</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">ToastContainer</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react-toastify</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="dl">"</span><span class="s2">react-toastify/dist/ReactToastify.css</span><span class="dl">"</span><span class="p">;</span> <span class="c1">//👇🏻 Websockets configuration</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">io</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">socket.io-client</span><span class="dl">"</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">App</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="kd">const</span> <span class="nx">socket</span> <span class="o">=</span> <span class="nx">io</span><span class="p">.</span><span class="nx">connect</span><span class="p">(</span><span class="dl">"</span><span class="s2">http://localhost:4000</span><span class="dl">"</span><span class="p">);</span> <span class="k">return</span> <span class="p">(</span> <span class="p"><></span> <span class="p"><</span><span class="nc">BrowserRouter</span><span class="p">></span> <span class="p"><</span><span class="nc">Routes</span><span class="p">></span> <span class="p"><</span><span class="nc">Route</span> <span class="na">path</span><span class="p">=</span><span class="s">'/'</span> <span class="na">element</span><span class="p">=</span><span class="si">{</span><span class="p"><</span><span class="nc">Login</span> <span class="na">socket</span><span class="p">=</span><span class="si">{</span><span class="nx">socket</span><span class="si">}</span> <span class="p">/></span><span class="si">}</span> <span class="p">/></span> <span class="p"><</span><span class="nc">Route</span> <span class="na">path</span><span class="p">=</span><span class="s">'/register'</span> <span class="na">element</span><span class="p">=</span><span class="si">{</span><span class="p"><</span><span class="nc">Register</span> <span class="na">socket</span><span class="p">=</span><span class="si">{</span><span class="nx">socket</span><span class="si">}</span> <span class="p">/></span><span class="si">}</span> <span class="p">/></span> <span class="p"><</span><span class="nc">Route</span> <span class="na">path</span><span class="p">=</span><span class="s">'/photos'</span> <span class="na">element</span><span class="p">=</span><span class="si">{</span><span class="p"><</span><span class="nc">Photos</span> <span class="na">socket</span><span class="p">=</span><span class="si">{</span><span class="nx">socket</span><span class="si">}</span> <span class="p">/></span><span class="si">}</span> <span class="p">/></span> <span class="p"><</span><span class="nc">Route</span> <span class="na">path</span><span class="p">=</span><span class="s">'/photo/upload'</span> <span class="na">element</span><span class="p">=</span><span class="si">{</span><span class="p"><</span><span class="nc">UploadPhoto</span> <span class="na">socket</span><span class="p">=</span><span class="si">{</span><span class="nx">socket</span><span class="si">}</span> <span class="p">/></span><span class="si">}</span> <span class="p">/></span> <span class="p"><</span><span class="nc">Route</span> <span class="na">path</span><span class="p">=</span><span class="s">'/user/photos'</span> <span class="na">element</span><span class="p">=</span><span class="si">{</span><span class="p"><</span><span class="nc">MyPhotos</span> <span class="na">socket</span><span class="p">=</span><span class="si">{</span><span class="nx">socket</span><span class="si">}</span> <span class="p">/></span><span class="si">}</span> <span class="p">/></span> <span class="p"><</span><span class="nc">Route</span> <span class="na">path</span><span class="p">=</span><span class="s">'/share/:user'</span> <span class="na">element</span><span class="p">=</span><span class="si">{</span><span class="p"><</span><span class="nc">SharePhoto</span> <span class="na">socket</span><span class="p">=</span><span class="si">{</span><span class="nx">socket</span><span class="si">}</span> <span class="p">/></span><span class="si">}</span> <span class="p">/></span> <span class="p"></</span><span class="nc">Routes</span><span class="p">></span> <span class="p"></</span><span class="nc">BrowserRouter</span><span class="p">></span> <span class="p"><</span><span class="nc">ToastContainer</span> <span class="p">/></span> <span class="p"></></span> <span class="p">);</span> <span class="p">};</span> <span class="k">export</span> <span class="k">default</span> <span class="nx">App</span><span class="p">;</span> |
Navigate into the src/index.css
file and copy the code below. It contains all the CSS required for styling this project.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
<span class="k">@import</span> <span class="sx">url("https://fonts.googleapis.com/css2?family=Space+Grotesk:[email protected];400;500;600;700&display=swap")</span><span class="p">;</span> <span class="o">*</span> <span class="p">{</span> <span class="nl">margin</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span> <span class="nl">box-sizing</span><span class="p">:</span> <span class="n">border-box</span><span class="p">;</span> <span class="nl">font-family</span><span class="p">:</span> <span class="s1">"Space Grotesk"</span><span class="p">,</span> <span class="nb">sans-serif</span><span class="p">;</span> <span class="nl">color</span><span class="p">:</span> <span class="m">#2b3a55</span><span class="p">;</span> <span class="p">}</span> <span class="nt">body</span> <span class="p">{</span> <span class="nl">padding</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span> <span class="nl">margin</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span> <span class="p">}</span> <span class="nt">button</span> <span class="p">{</span> <span class="nl">border</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span> <span class="nl">outline</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span> <span class="nl">cursor</span><span class="p">:</span> <span class="nb">pointer</span><span class="p">;</span> <span class="p">}</span> <span class="nt">input</span> <span class="p">{</span> <span class="nl">padding</span><span class="p">:</span> <span class="m">10px</span> <span class="m">15px</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.navbar</span> <span class="p">{</span> <span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span> <span class="nl">min-height</span><span class="p">:</span> <span class="m">10vh</span><span class="p">;</span> <span class="nl">padding</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span> <span class="nl">display</span><span class="p">:</span> <span class="n">flex</span><span class="p">;</span> <span class="nl">align-items</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span> <span class="nl">justify-content</span><span class="p">:</span> <span class="n">space-between</span><span class="p">;</span> <span class="nl">background-color</span><span class="p">:</span> <span class="m">#f2e5e5</span><span class="p">;</span> <span class="nl">position</span><span class="p">:</span> <span class="n">sticky</span><span class="p">;</span> <span class="nl">top</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span> <span class="nl">z-index</span><span class="p">:</span> <span class="m">10</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.nav__BtnGroup</span> <span class="nt">a</span><span class="o">,</span> <span class="nc">.nav__BtnGroup</span> <span class="nt">button</span> <span class="p">{</span> <span class="nl">padding</span><span class="p">:</span> <span class="m">15px</span><span class="p">;</span> <span class="nl">width</span><span class="p">:</span> <span class="m">200px</span><span class="p">;</span> <span class="nl">font-size</span><span class="p">:</span> <span class="m">16px</span><span class="p">;</span> <span class="nl">cursor</span><span class="p">:</span> <span class="nb">pointer</span><span class="p">;</span> <span class="nl">outline</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span> <span class="nl">background-color</span><span class="p">:</span> <span class="m">#fff</span><span class="p">;</span> <span class="nl">border</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span> <span class="nl">border-radius</span><span class="p">:</span> <span class="m">3px</span><span class="p">;</span> <span class="nl">text-decoration</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.nav__BtnGroup</span> <span class="nt">a</span> <span class="p">{</span> <span class="nl">margin-right</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.nav__BtnGroup</span> <span class="nt">a</span><span class="nd">:hover</span><span class="o">,</span> <span class="nc">.nav__BtnGroup</span> <span class="nt">button</span><span class="nd">:hover</span> <span class="p">{</span> <span class="nl">background-color</span><span class="p">:</span> <span class="m">#ce7777</span><span class="p">;</span> <span class="nl">color</span><span class="p">:</span> <span class="m">#fff</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.login</span><span class="o">,</span> <span class="nc">.register</span> <span class="p">{</span> <span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span> <span class="nl">min-height</span><span class="p">:</span> <span class="m">100vh</span><span class="p">;</span> <span class="nl">display</span><span class="p">:</span> <span class="n">flex</span><span class="p">;</span> <span class="nl">align-items</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span> <span class="nl">justify-content</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span> <span class="nl">flex-direction</span><span class="p">:</span> <span class="n">column</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.login__form</span><span class="o">,</span> <span class="nc">.register__form</span> <span class="p">{</span> <span class="nl">width</span><span class="p">:</span> <span class="m">500px</span><span class="p">;</span> <span class="nl">display</span><span class="p">:</span> <span class="n">flex</span><span class="p">;</span> <span class="nl">flex-direction</span><span class="p">:</span> <span class="n">column</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.input</span> <span class="p">{</span> <span class="nl">padding</span><span class="p">:</span> <span class="m">12px</span> <span class="m">10px</span><span class="p">;</span> <span class="nl">margin-bottom</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span> <span class="nl">border-radius</span><span class="p">:</span> <span class="m">4px</span><span class="p">;</span> <span class="nl">border</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="m">#e8c4c4</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.loginBtn</span><span class="o">,</span> <span class="nc">.registerBtn</span> <span class="p">{</span> <span class="nl">padding</span><span class="p">:</span> <span class="m">15px</span><span class="p">;</span> <span class="nl">font-size</span><span class="p">:</span> <span class="m">16px</span><span class="p">;</span> <span class="nl">cursor</span><span class="p">:</span> <span class="nb">pointer</span><span class="p">;</span> <span class="nl">background-color</span><span class="p">:</span> <span class="m">#f2e5e5</span><span class="p">;</span> <span class="nl">color</span><span class="p">:</span> <span class="m">#2b3a55</span><span class="p">;</span> <span class="nl">border</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span> <span class="nl">outline</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span> <span class="nl">border-radius</span><span class="p">:</span> <span class="m">5px</span><span class="p">;</span> <span class="nl">margin-bottom</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.loginBtn</span><span class="nd">:hover</span><span class="o">,</span> <span class="nc">.registerBtn</span><span class="nd">:hover</span> <span class="p">{</span> <span class="nl">background-color</span><span class="p">:</span> <span class="m">#ce7777</span><span class="p">;</span> <span class="nl">color</span><span class="p">:</span> <span class="m">#fff</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.link</span> <span class="p">{</span> <span class="nl">color</span><span class="p">:</span> <span class="m">#ce7777</span><span class="p">;</span> <span class="nl">cursor</span><span class="p">:</span> <span class="nb">pointer</span><span class="p">;</span> <span class="nl">text-decoration</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.photoContainer</span> <span class="p">{</span> <span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span> <span class="nl">min-height</span><span class="p">:</span> <span class="m">90vh</span><span class="p">;</span> <span class="nl">padding</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span> <span class="nl">display</span><span class="p">:</span> <span class="n">flex</span><span class="p">;</span> <span class="nl">align-items</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span> <span class="nl">justify-content</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span> <span class="nl">flex-wrap</span><span class="p">:</span> <span class="n">wrap</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.photoContainer</span> <span class="o">></span> <span class="o">*</span> <span class="p">{</span> <span class="nl">margin</span><span class="p">:</span> <span class="m">15px</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.photo</span> <span class="p">{</span> <span class="nl">width</span><span class="p">:</span> <span class="m">300px</span><span class="p">;</span> <span class="nl">height</span><span class="p">:</span> <span class="m">350px</span><span class="p">;</span> <span class="nl">position</span><span class="p">:</span> <span class="nb">relative</span><span class="p">;</span> <span class="nl">border-radius</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span> <span class="nl">box-shadow</span><span class="p">:</span> <span class="m">0</span> <span class="m">2px</span> <span class="m">8px</span> <span class="m">0</span> <span class="n">rgba</span><span class="p">(</span><span class="m">99</span><span class="p">,</span> <span class="m">99</span><span class="p">,</span> <span class="m">99</span><span class="p">,</span> <span class="m">0.2</span><span class="p">);</span> <span class="p">}</span> <span class="nc">.imageContainer</span> <span class="p">{</span> <span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span> <span class="nl">position</span><span class="p">:</span> <span class="nb">relative</span><span class="p">;</span> <span class="nl">height</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.photo__image</span> <span class="p">{</span> <span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span> <span class="nl">height</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span> <span class="nl">position</span><span class="p">:</span> <span class="nb">absolute</span><span class="p">;</span> <span class="nl">object-fit</span><span class="p">:</span> <span class="n">cover</span><span class="p">;</span> <span class="nl">border-radius</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.upvoteIcon</span> <span class="p">{</span> <span class="nl">background-color</span><span class="p">:</span> <span class="m">#fff</span><span class="p">;</span> <span class="nl">padding</span><span class="p">:</span> <span class="m">10px</span> <span class="m">20px</span><span class="p">;</span> <span class="nl">position</span><span class="p">:</span> <span class="nb">absolute</span><span class="p">;</span> <span class="nl">bottom</span><span class="p">:</span> <span class="m">5px</span><span class="p">;</span> <span class="nl">right</span><span class="p">:</span> <span class="m">5px</span><span class="p">;</span> <span class="nl">cursor</span><span class="p">:</span> <span class="nb">pointer</span><span class="p">;</span> <span class="nl">border-radius</span><span class="p">:</span> <span class="m">5px</span><span class="p">;</span> <span class="nl">display</span><span class="p">:</span> <span class="n">flex</span><span class="p">;</span> <span class="nl">flex-direction</span><span class="p">:</span> <span class="n">column</span><span class="p">;</span> <span class="nl">align-items</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.upvoteIcon</span><span class="nd">:hover</span> <span class="p">{</span> <span class="nl">background-color</span><span class="p">:</span> <span class="m">#f2e5e5</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.uploadContainer</span> <span class="p">{</span> <span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span> <span class="nl">min-height</span><span class="p">:</span> <span class="m">100vh</span><span class="p">;</span> <span class="nl">display</span><span class="p">:</span> <span class="n">flex</span><span class="p">;</span> <span class="nl">align-items</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span> <span class="nl">justify-content</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.uploadText</span> <span class="p">{</span> <span class="nl">width</span><span class="p">:</span> <span class="m">80%</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.uploadText</span> <span class="nt">form</span> <span class="p">{</span> <span class="nl">display</span><span class="p">:</span> <span class="n">flex</span><span class="p">;</span> <span class="nl">flex-direction</span><span class="p">:</span> <span class="n">column</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.uploadText</span> <span class="o">></span> <span class="nt">h2</span> <span class="p">{</span> <span class="nl">margin-bottom</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.uploadBtn</span> <span class="p">{</span> <span class="nl">margin-top</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span> <span class="nl">padding</span><span class="p">:</span> <span class="m">10px</span><span class="p">;</span> <span class="nl">background-color</span><span class="p">:</span> <span class="m">#ce7777</span><span class="p">;</span> <span class="nl">color</span><span class="p">:</span> <span class="m">#fff</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.copyDiv</span> <span class="p">{</span> <span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span> <span class="nl">display</span><span class="p">:</span> <span class="n">flex</span><span class="p">;</span> <span class="nl">align-items</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span> <span class="nl">justify-content</span><span class="p">:</span> <span class="nb">center</span><span class="p">;</span> <span class="p">}</span> <span class="nc">.copyContainer</span> <span class="p">{</span> <span class="nl">margin-top</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span> <span class="nl">padding</span><span class="p">:</span> <span class="m">15px</span><span class="p">;</span> <span class="nl">cursor</span><span class="p">:</span> <span class="nb">pointer</span><span class="p">;</span> <span class="nl">background-color</span><span class="p">:</span> <span class="m">#ce7777</span><span class="p">;</span> <span class="nl">border-radius</span><span class="p">:</span> <span class="m">5px</span><span class="p">;</span> <span class="p">}</span> |
The Login page
Copy the code below into the Login
component. The application accepts the username and password from the user.
1 2 3 4 5 |
<span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useEffect</span><span class="p">,</span> <span class="nx">useState</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">Link</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react-router-dom</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">useNavigate</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react-router-dom</span><span class="dl">"</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">Login</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">socket</span> <span class="p">})</span> <span class="o">=></span> <span class="p">{</span> <span class="kd">const</span> <span class="nx">navigate</span> <span class="o">=</span> <span class="nx">useNavigate</span><span class="p">();</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">username</span><span class="p">,</span> <span class="nx">setUsername</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="dl">""</span><span class="p">);</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">password</span><span class="p">,</span> <span class="nx">setPassword</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="dl">""</span><span class="p">);</span> <span class="kd">const</span> <span class="nx">handleSignIn</span> <span class="o">=</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="nx">username</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span> <span class="o">&&</span> <span class="nx">password</span><span class="p">.</span><span class="nx">trim</span><span class="p">())</span> <span class="p">{</span> <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">({</span> <span class="nx">username</span><span class="p">,</span> <span class="nx">password</span> <span class="p">});</span> <span class="nx">setPassword</span><span class="p">(</span><span class="dl">""</span><span class="p">);</span> <span class="nx">setUsername</span><span class="p">(</span><span class="dl">""</span><span class="p">);</span> <span class="p">}</span> <span class="p">};</span> <span class="k">return</span> <span class="p">(</span> <span class="p"><</span><span class="nt">div</span> <span class="na">className</span><span class="p">=</span><span class="s">'login'</span><span class="p">></span> <span class="p"><</span><span class="nt">h2</span> <span class="na">style</span><span class="p">=</span><span class="si">{</span><span class="p">{</span> <span class="na">marginBottom</span><span class="p">:</span> <span class="dl">"</span><span class="s2">30px</span><span class="dl">"</span> <span class="p">}</span><span class="si">}</span><span class="p">></span>Login<span class="p"></</span><span class="nt">h2</span><span class="p">></span> <span class="p"><</span><span class="nt">form</span> <span class="na">className</span><span class="p">=</span><span class="s">'login__form'</span> <span class="na">method</span><span class="p">=</span><span class="s">'POST'</span> <span class="na">onSubmit</span><span class="p">=</span><span class="si">{</span><span class="nx">handleSignIn</span><span class="si">}</span><span class="p">></span> <span class="p"><</span><span class="nt">label</span> <span class="na">htmlFor</span><span class="p">=</span><span class="s">'username'</span><span class="p">></span>Username<span class="p"></</span><span class="nt">label</span><span class="p">></span> <span class="p"><</span><span class="nt">input</span> <span class="na">type</span><span class="p">=</span><span class="s">'text'</span> <span class="na">className</span><span class="p">=</span><span class="s">'input'</span> <span class="na">name</span><span class="p">=</span><span class="s">'username'</span> <span class="na">id</span><span class="p">=</span><span class="s">'username'</span> <span class="na">required</span> <span class="na">value</span><span class="p">=</span><span class="si">{</span><span class="nx">username</span><span class="si">}</span> <span class="na">onChange</span><span class="p">=</span><span class="si">{</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=></span> <span class="nx">setUsername</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">)</span><span class="si">}</span> <span class="p">/></span> <span class="p"><</span><span class="nt">label</span> <span class="na">htmlFor</span><span class="p">=</span><span class="s">'password'</span><span class="p">></span>Password<span class="p"></</span><span class="nt">label</span><span class="p">></span> <span class="p"><</span><span class="nt">input</span> <span class="na">type</span><span class="p">=</span><span class="s">'password'</span> <span class="na">className</span><span class="p">=</span><span class="s">'input'</span> <span class="na">name</span><span class="p">=</span><span class="s">'password'</span> <span class="na">id</span><span class="p">=</span><span class="s">'password'</span> <span class="na">required</span> <span class="na">minLength</span><span class="p">=</span><span class="si">{</span><span class="mi">6</span><span class="si">}</span> <span class="na">value</span><span class="p">=</span><span class="si">{</span><span class="nx">password</span><span class="si">}</span> <span class="na">onChange</span><span class="p">=</span><span class="si">{</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=></span> <span class="nx">setPassword</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">)</span><span class="si">}</span> <span class="p">/></span> <span class="p"><</span><span class="nt">button</span> <span class="na">className</span><span class="p">=</span><span class="s">'loginBtn'</span><span class="p">></span>LOG IN<span class="p"></</span><span class="nt">button</span><span class="p">></span> <span class="p"><</span><span class="nt">p</span> <span class="na">style</span><span class="p">=</span><span class="si">{</span><span class="p">{</span> <span class="na">textAlign</span><span class="p">:</span> <span class="dl">"</span><span class="s2">center</span><span class="dl">"</span> <span class="p">}</span><span class="si">}</span><span class="p">></span> Don't have an account?<span class="si">{</span><span class="dl">"</span><span class="s2"> </span><span class="dl">"</span><span class="si">}</span> <span class="p"><</span><span class="nc">Link</span> <span class="na">className</span><span class="p">=</span><span class="s">'link'</span> <span class="na">to</span><span class="p">=</span><span class="s">'/register'</span><span class="p">></span> Create one <span class="p"></</span><span class="nc">Link</span><span class="p">></span> <span class="p"></</span><span class="nt">p</span><span class="p">></span> <span class="p"></</span><span class="nt">form</span><span class="p">></span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> <span class="p">);</span> <span class="p">};</span> <span class="k">export</span> <span class="k">default</span> <span class="nx">Login</span><span class="p">;</span> |
The Register page
Copy the code below into the Register.js
file to accepts the user’s email, username and password.
1 2 3 4 5 |
<span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useState</span><span class="p">,</span> <span class="nx">useEffect</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">Link</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react-router-dom</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">useNavigate</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react-router-dom</span><span class="dl">"</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">Register</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">socket</span> <span class="p">})</span> <span class="o">=></span> <span class="p">{</span> <span class="kd">const</span> <span class="nx">navigate</span> <span class="o">=</span> <span class="nx">useNavigate</span><span class="p">();</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">username</span><span class="p">,</span> <span class="nx">setUsername</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="dl">""</span><span class="p">);</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">password</span><span class="p">,</span> <span class="nx">setPassword</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="dl">""</span><span class="p">);</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">email</span><span class="p">,</span> <span class="nx">setEmail</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="dl">""</span><span class="p">);</span> <span class="kd">const</span> <span class="nx">handleRegister</span> <span class="o">=</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span> <span class="k">if</span> <span class="p">(</span><span class="nx">username</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span> <span class="o">&&</span> <span class="nx">password</span><span class="p">.</span><span class="nx">trim</span><span class="p">()</span> <span class="o">&&</span> <span class="nx">email</span><span class="p">.</span><span class="nx">trim</span><span class="p">())</span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">({</span> <span class="nx">username</span><span class="p">,</span> <span class="nx">email</span><span class="p">,</span> <span class="nx">password</span> <span class="p">});</span> <span class="nx">setPassword</span><span class="p">(</span><span class="dl">""</span><span class="p">);</span> <span class="nx">setUsername</span><span class="p">(</span><span class="dl">""</span><span class="p">);</span> <span class="nx">setEmail</span><span class="p">(</span><span class="dl">""</span><span class="p">);</span> <span class="p">}</span> <span class="p">};</span> <span class="k">return</span> <span class="p">(</span> <span class="p"><</span><span class="nt">div</span> <span class="na">className</span><span class="p">=</span><span class="s">'register'</span><span class="p">></span> <span class="p"><</span><span class="nt">h2</span> <span class="na">style</span><span class="p">=</span><span class="si">{</span><span class="p">{</span> <span class="na">marginBottom</span><span class="p">:</span> <span class="dl">"</span><span class="s2">30px</span><span class="dl">"</span> <span class="p">}</span><span class="si">}</span><span class="p">></span>Register<span class="p"></</span><span class="nt">h2</span><span class="p">></span> <span class="p"><</span><span class="nt">form</span> <span class="na">className</span><span class="p">=</span><span class="s">'register__form'</span> <span class="na">method</span><span class="p">=</span><span class="s">'POST'</span> <span class="na">onSubmit</span><span class="p">=</span><span class="si">{</span><span class="nx">handleRegister</span><span class="si">}</span><span class="p">></span> <span class="p"><</span><span class="nt">label</span> <span class="na">htmlFor</span><span class="p">=</span><span class="s">'email'</span><span class="p">></span>Email Address<span class="p"></</span><span class="nt">label</span><span class="p">></span> <span class="p"><</span><span class="nt">input</span> <span class="na">type</span><span class="p">=</span><span class="s">'email'</span> <span class="na">className</span><span class="p">=</span><span class="s">'input'</span> <span class="na">name</span><span class="p">=</span><span class="s">'email'</span> <span class="na">id</span><span class="p">=</span><span class="s">'email'</span> <span class="na">required</span> <span class="na">value</span><span class="p">=</span><span class="si">{</span><span class="nx">email</span><span class="si">}</span> <span class="na">onChange</span><span class="p">=</span><span class="si">{</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=></span> <span class="nx">setEmail</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">)</span><span class="si">}</span> <span class="p">/></span> <span class="p"><</span><span class="nt">label</span> <span class="na">htmlFor</span><span class="p">=</span><span class="s">'username'</span><span class="p">></span>Username<span class="p"></</span><span class="nt">label</span><span class="p">></span> <span class="p"><</span><span class="nt">input</span> <span class="na">type</span><span class="p">=</span><span class="s">'text'</span> <span class="na">className</span><span class="p">=</span><span class="s">'input'</span> <span class="na">name</span><span class="p">=</span><span class="s">'username'</span> <span class="na">id</span><span class="p">=</span><span class="s">'username'</span> <span class="na">required</span> <span class="na">value</span><span class="p">=</span><span class="si">{</span><span class="nx">username</span><span class="si">}</span> <span class="na">onChange</span><span class="p">=</span><span class="si">{</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=></span> <span class="nx">setUsername</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">)</span><span class="si">}</span> <span class="p">/></span> <span class="p"><</span><span class="nt">label</span> <span class="na">htmlFor</span><span class="p">=</span><span class="s">'password'</span><span class="p">></span>Password<span class="p"></</span><span class="nt">label</span><span class="p">></span> <span class="p"><</span><span class="nt">input</span> <span class="na">type</span><span class="p">=</span><span class="s">'password'</span> <span class="na">className</span><span class="p">=</span><span class="s">'input'</span> <span class="na">name</span><span class="p">=</span><span class="s">'password'</span> <span class="na">id</span><span class="p">=</span><span class="s">'password'</span> <span class="na">required</span> <span class="na">minLength</span><span class="p">=</span><span class="si">{</span><span class="mi">6</span><span class="si">}</span> <span class="na">value</span><span class="p">=</span><span class="si">{</span><span class="nx">password</span><span class="si">}</span> <span class="na">onChange</span><span class="p">=</span><span class="si">{</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="o">=></span> <span class="nx">setPassword</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">)</span><span class="si">}</span> <span class="p">/></span> <span class="p"><</span><span class="nt">button</span> <span class="na">className</span><span class="p">=</span><span class="s">'registerBtn'</span><span class="p">></span>REGISTER<span class="p"></</span><span class="nt">button</span><span class="p">></span> <span class="p"><</span><span class="nt">p</span> <span class="na">style</span><span class="p">=</span><span class="si">{</span><span class="p">{</span> <span class="na">textAlign</span><span class="p">:</span> <span class="dl">"</span><span class="s2">center</span><span class="dl">"</span> <span class="p">}</span><span class="si">}</span><span class="p">></span> Already have an account?<span class="si">{</span><span class="dl">"</span><span class="s2"> </span><span class="dl">"</span><span class="si">}</span> <span class="p"><</span><span class="nc">Link</span> <span class="na">className</span><span class="p">=</span><span class="s">'link'</span> <span class="na">to</span><span class="p">=</span><span class="s">'/'</span><span class="p">></span> Sign in <span class="p"></</span><span class="nc">Link</span><span class="p">></span> <span class="p"></</span><span class="nt">p</span><span class="p">></span> <span class="p"></</span><span class="nt">form</span><span class="p">></span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> <span class="p">);</span> <span class="p">};</span> <span class="k">export</span> <span class="k">default</span> <span class="nx">Register</span><span class="p">;</span> |
The Photos component
This component is divided into two sub-components which are the navigation and the main container containing the available images.
Copy the code below into the Photos.js
file.
1 2 3 4 5 |
<span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useEffect</span><span class="p">,</span> <span class="nx">useState</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="nx">Nav</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./Nav</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="nx">PhotoContainer</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">./PhotoContainer</span><span class="dl">"</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">Home</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">socket</span> <span class="p">})</span> <span class="o">=></span> <span class="p">{</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">photos</span><span class="p">,</span> <span class="nx">setPhotos</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">([</span> <span class="p">{</span> <span class="na">id</span><span class="p">:</span> <span class="dl">"</span><span class="s2">1</span><span class="dl">"</span><span class="p">,</span> <span class="na">image_url</span><span class="p">:</span> <span class="dl">"</span><span class="s2">https://raw.githubusercontent.com/novuhq/blog/main/upvote-app-with-react-and-nodejs/server/images/dog1.jpg</span><span class="dl">"</span><span class="p">,</span> <span class="na">vote_count</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="p">},</span> <span class="p">{</span> <span class="na">id</span><span class="p">:</span> <span class="dl">"</span><span class="s2">2</span><span class="dl">"</span><span class="p">,</span> <span class="na">image_url</span><span class="p">:</span> <span class="dl">"</span><span class="s2">https://raw.githubusercontent.com/novuhq/blog/main/upvote-app-with-react-and-nodejs/server/images/dog2.jpg</span><span class="dl">"</span><span class="p">,</span> <span class="na">vote_count</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="p">},</span> <span class="p">]);</span> <span class="k">return</span> <span class="p">(</span> <span class="p"><</span><span class="nt">div</span><span class="p">></span> <span class="p"><</span><span class="nc">Nav</span> <span class="p">/></span> <span class="p"><</span><span class="nc">PhotoContainer</span> <span class="na">photos</span><span class="p">=</span><span class="si">{</span><span class="nx">photos</span><span class="si">}</span> <span class="na">socket</span><span class="p">=</span><span class="si">{</span><span class="nx">socket</span><span class="si">}</span> <span class="p">/></span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> <span class="p">);</span> <span class="p">};</span> <span class="k">export</span> <span class="k">default</span> <span class="nx">Home</span><span class="p">;</span> |
Create the Nav and PhotoContainer sub-components.
1 2 |
<span class="nb">touch </span>Nav.js PhotoContainer.js |
Copy the code below into the Nav.js
file.
1 2 3 4 |
<span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">Link</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react-router-dom</span><span class="dl">"</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">Nav</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="k">return</span> <span class="p">(</span> <span class="p"><</span><span class="nt">nav</span> <span class="na">className</span><span class="p">=</span><span class="s">'navbar'</span><span class="p">></span> <span class="p"><</span><span class="nt">h3</span><span class="p">></span>PhotoShare<span class="p"></</span><span class="nt">h3</span><span class="p">></span> <span class="p"><</span><span class="nt">div</span> <span class="na">className</span><span class="p">=</span><span class="s">'nav__BtnGroup'</span><span class="p">></span> <span class="p"><</span><span class="nc">Link</span> <span class="na">to</span><span class="p">=</span><span class="s">'/user/photos'</span> <span class="na">style</span><span class="p">=</span><span class="si">{</span><span class="p">{</span> <span class="na">marginRight</span><span class="p">:</span> <span class="dl">"</span><span class="s2">10px</span><span class="dl">"</span> <span class="p">}</span><span class="si">}</span><span class="p">></span> My Photos <span class="p"></</span><span class="nc">Link</span><span class="p">></span> <span class="p"><</span><span class="nc">Link</span> <span class="na">to</span><span class="p">=</span><span class="s">'/photo/upload'</span><span class="p">></span>Upload Photo<span class="p"></</span><span class="nc">Link</span><span class="p">></span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> <span class="p"></</span><span class="nt">nav</span><span class="p">></span> <span class="p">);</span> <span class="p">};</span> <span class="k">export</span> <span class="k">default</span> <span class="nx">Nav</span><span class="p">;</span> |
Update the PhotoContainer.js
file as below:
1 2 3 4 |
<span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useEffect</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react</span><span class="dl">"</span><span class="p">;</span> <span class="k">import</span> <span class="p">{</span> <span class="nx">MdOutlineArrowUpward</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react-icons/md</span><span class="dl">"</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">PhotoContainer</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">photos</span><span class="p">,</span> <span class="nx">socket</span> <span class="p">})</span> <span class="o">=></span> <span class="p">{</span> <span class="kd">const</span> <span class="nx">handleUpvote</span> <span class="o">=</span> <span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">Upvote</span><span class="dl">"</span><span class="p">,</span> <span class="nx">id</span><span class="p">);</span> <span class="p">};</span> <span class="k">return</span> <span class="p">(</span> <span class="p"><</span><span class="nt">main</span> <span class="na">className</span><span class="p">=</span><span class="s">'photoContainer'</span><span class="p">></span> <span class="si">{</span><span class="nx">photos</span><span class="p">.</span><span class="nx">map</span><span class="p">((</span><span class="nx">photo</span><span class="p">)</span> <span class="o">=></span> <span class="p">(</span> <span class="p"><</span><span class="nt">div</span> <span class="na">className</span><span class="p">=</span><span class="s">'photo'</span> <span class="na">key</span><span class="p">=</span><span class="si">{</span><span class="nx">photo</span><span class="p">.</span><span class="nx">id</span><span class="si">}</span><span class="p">></span> <span class="p"><</span><span class="nt">div</span> <span class="na">className</span><span class="p">=</span><span class="s">'imageContainer'</span><span class="p">></span> <span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="p">=</span><span class="si">{</span><span class="nx">photo</span><span class="p">.</span><span class="nx">image_url</span><span class="si">}</span> <span class="na">alt</span><span class="p">=</span><span class="si">{</span><span class="nx">photo</span><span class="p">.</span><span class="nx">id</span><span class="si">}</span> <span class="na">className</span><span class="p">=</span><span class="s">'photo__image'</span> <span class="p">/></span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> <span class="p"><</span><span class="nt">button</span> <span class="na">className</span><span class="p">=</span><span class="s">'upvoteIcon'</span> <span class="na">onClick</span><span class="p">=</span><span class="si">{</span><span class="p">()</span> <span class="o">=></span> <span class="nx">handleUpvote</span><span class="p">(</span><span class="nx">photo</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span><span class="si">}</span><span class="p">></span> <span class="p"><</span><span class="nc">MdOutlineArrowUpward</span> <span class="na">style</span><span class="p">=</span><span class="si">{</span><span class="p">{</span> <span class="na">fontSize</span><span class="p">:</span> <span class="dl">"</span><span class=" |