Our great sponsors
-
SurveyJS
Open-Source JSON Form Builder to Create Dynamic Forms Right in Your App. With SurveyJS form UI libraries, you can build and style forms in a fully-integrated drag & drop form builder, render them in your JS app, and store form submission data in any backend, inc. PHP, ASP.NET Core, and Node.js.
While programming, programmers encounter various challenges, which make them solicit help with solving these problems. Forums provide a tech community of enthusiasts who can assist with these problems. We will be building a forum site with NextJs on the Front-end and Strapi for content management
We will build the front-end of our forum application with Next.js. Next.js is an open-source framework built on Node.js to allow React applications to be rendered on the server-side.
import React, { useState } from "react"; import style from "../../styles/Home.module.css"; import Link from "next/link"; function Displayforum() { const [show, setShow] = useState(false); return ( Display forum Ask a question Login Questions Posted By: Victory Tuduo Description of the Question Answers Post setShow(!show)}> {show ? "Hide Answers" : "Show Answers"} {show ? (
) : null} ); } export default Displayforum;Miracle
Try doing it Like this
Enter fullscreen mode Exit fullscreen modeThis component handles the layout of our display forum page. We also have a button here that directs the user to the page to upload new questions.
Meanwhile, in
upload.js
we have the following:
import React from "react"; import Uploadforum from "./Components/Uploadforum"; function upload() { return (
); } export default upload;Enter fullscreen mode Exit fullscreen modeHere, we simply added an import for the
Uploadforum
component into our page. InUploadforum.js
file we have a simple form to create new questions:
import React from "react"; import style from "../../styles/Home.module.css"; import Link from "next/Link"; function Uploadforum() { return (
Ask a question
Forum<button>Submit Question</button> </form> </div> </div> ); } export default Uploadforum; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Finally, we have the following styles in <code>Home.module.css</code><br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> .container { min-height: 100vh; padding: 0 0.5rem; height: 100vh; font-family: monospace; } /* display forum page */ .topcont { display: flex; justify-content: space-between; align-items: center; padding: 5px 8px; } .topcont button, .inputanswer button, .formcont button, .showanswer { border: none; color: #fff; background: dodgerblue; border-radius: 8px; padding: 10px 15px; outline: none; margin: 8px; } .topcont button:hover { cursor: pointer; transform: scale(1.2); } .heading { font-weight: bold; } .subheading { font-weight: 500; text-transform: uppercase; } .userinfo { font-size: 18px; font-weight: 600; } .questioncont { min-height: 300px; padding: 15px 14px; box-shadow: 12px 12px 36px rgba(0, 0, 0, 0.12); } .answercont { min-height: 300px; padding: 5px 3px 5px 15px; } .answers { height: 300px; overflow-x: scroll; } .inputanswer { margin-bottom: 8px; } .inputanswer textarea { width: 100%; resize: none; padding: 5px 8px; } .showanswer { border: 1px solid dodgerblue; background: #fff; color: dodgerblue; transition: 0.4s ease-in-out; } .showanswer:hover { background: dodgerblue; color: #fff; } .eachanswer { border-radius: 15px; background: #e7e7e7; padding: 8px 15px; margin-bottom: 10px; } .username { font-weight: bold; text-transform: uppercase; } .answertext { font-family: Montserrat; font-size: 14px; font-weight: 500; } /* upload a question page */ .uploadpage { min-height: 100vh; } .formcont { min-width: 100vw; display: flex; justify-content: center; align-items: center; } .uploadform { display: flex; flex-direction: column; min-width: 500px; padding-top: 10px; } .uploadform input, .uploadform textarea { resize: none; width: 100%; margin: 8px; padding: 5px; } </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>All of this makes up the layout of our pages.</p> <h2> <a name="getting-data-from-strapi" href="#getting-data-from-strapi"> </a> Getting data from Strapi: </h2> <h2> <a name="setting-up-our-fetch-request" href="#setting-up-our-fetch-request"> </a> Setting up our Fetch Request </h2> <p>In this section, we will fetch our data from Strapi and display it in our app. We will be using <a href="https://axios-http.com/docs/intro">Axios</a> to perform our fetch operations.</p> <p>We will install this via CLI:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code> npm <span class="nb">install </span>axios </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Create a file <code>index.js</code> in the API folder. Here, we will set up our fetch request:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import axios from "axios"; const url = "http://localhost:1337/strapi-forums"; export const readForum = () => axios.get(url); export const createQuestion = (newQuestion) => axios.post(url, newQuestion); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Above, we added import for <code>axios</code>, the URL to fetch our data, and exported functions to read and create data from our forum.</p> <p>We’ll import these functions into our app in our <code>index.js</code> file:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { readForum, createQuestion } from "./api"; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <h2> <a name="fetching-data-from-strapi" href="#fetching-data-from-strapi"> </a> Fetching Data from Strapi </h2> <p>We will fetch the data from Strapi in our <code>index.js</code> file and pass it to <code>Displayforum.js</code> component to display it:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { react, useState, useEffect } from "react"; ... const [question, setQuestions] = useState({}); const [response, setResponse] = useState([]); useEffect(() => { const fetchData = async () => { const result = await readForum(); setResponse(result.data); }; fetchData(); }, []); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Here, we fetched our data from Strapi and assigned it to <code>response</code> with the React <code>useState</code> hook. We have a <code>useEffect</code> function that makes the request when our component mounts.</p> <p>Now, we pass this <code>response</code> down to our <code>Displayforum</code> component.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <Displayforum response={response} /> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <h2> <a name="displaying-data-from-strap" href="#displaying-data-from-strap"> </a> Displaying Data from Strap </h2> <p>To display our data in our <code>Displayforum.js</code> file, we will map our responses and render our components. Before we do this, we will create two additional text fields in our Strapi CollectionCollection: <code>Username</code> and <code>Answername</code>.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c2XelJbV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635543765246_created%2Bnew%2Bfields.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c2XelJbV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635543765246_created%2Bnew%2Bfields.jpg" alt="" loading="lazy" width="792" height="468"></a></p> <p>Back in our <code>Displayforum</code> component we will proceed with displaying our data:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... function Displayforum({ response }) { ... {response.map((response, index) => ( <div key={index}> <div className={style.userinfo}> ... <p className={style.answertext}>Try doing it Like this</p> </div> </div> ) : null} </div> </div> ))} </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Here, we wrapped up our components to map through <code>response</code> and display this component as many times as the number of responses. To display our Strapi data, we simply reference it. We can get our <code>Username</code> with this code:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> response.Username </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can now add this to our component and display it:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <p>Posted By: {response.Username}</p> ... <p className={style.question}>{response.Questions}</p> ... <p className={style.username}>{response.Answername}</p> <p className={style.answertext}>{response.Answers}</p> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We have successfully added the data from our CollectionCollection to our <code>front-end</code> to view this in the browser. Run the following command in the CLI:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code> npm run dev </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>In your browser, you will have an output similar to the image below:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0X_EJPA4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635545169076_got%2Bdata%2Bfrom%2BStrapi.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0X_EJPA4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635545169076_got%2Bdata%2Bfrom%2BStrapi.jpg" alt="" loading="lazy" width="880" height="399"></a></p> <p>After this, we will add functionality to add new questions to Strapi.</p> <h2> <a name="adding-data-to-strapi" href="#adding-data-to-strapi"> </a> Adding data to Strapi </h2> <p>In our <code>Uploadforum.js</code> file, we will add functionality to upload the contents of the form to Strapi. First, we will create two state variables to store the text from our <code>inputs</code>.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { React, useState } from "react"; ... const [name, setName] = useState(""); const [description, setDescription] = useState(""); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then we set these variables to the value of our form <code>input</code>.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <input type="text" placeholder="Enter your title" maxLength="74" value={name} onChange={(e) => setName(e.target.value)} /> <textarea type="text" placeholder="Enter your description" rows="8" value={description} onChange={(e) => setDescription(e.target.value)} /> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Also we will a function to send these variables when we click our <code>button</code>.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <button onClick={() => sendData()}>Submit Question</button> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can create the <code>sendData</code> function above our <code>return</code>.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> const sendData = () => { }; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>For our create functionality we will import the <code>createQuestion</code> function we defined in our <code>api</code> folder.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { createQuestion } from "../api"; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then we pass in our data to this function.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> const sendData = () => { const newQuestion = { Title: name, Questions: description, }; createQuestion(newQuestion); }; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can now upload new questions to our Strapi <code>collection</code>. We will add the <code>Username</code> when we cover user authentication.</p> <p>Next up, we will add functionality to answer questions in our <code>Displayforum</code> component.</p> <h2> <a name="adding-functionality-to-answer-questions" href="#adding-functionality-to-answer-questions"> </a> Adding Functionality to Answer Questions </h2> <p>Since we set a text field for our answers in our <code>collection</code>, it can only take in one value. To have multiple answers for a question, we will delete the Answers field and create another field for our Answers of type <code>json</code>.</p> <p>With that done, here is an example of what a response from our API would look like:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6ji2Py_9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635601446784_new%2Bresponse.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6ji2Py_9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635601446784_new%2Bresponse.jpg" alt="" loading="lazy" width="586" height="423"></a></p> <p>To display our answers, we will map through <code>Answers</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> {response.Answers.map((answers, i) => ( <div className={style.eachanswer} key={i}> <p className={style.username}>{response.Answername}</p> <p className={style.answertext}>{answers}</p> </div> ))} </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Now in our browser, if we add more <code>answers</code> to our JSON collection, we can see them displayed on our page.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jt0sMsr0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635602131051_added%2Banswers%2Bjson.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jt0sMsr0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635602131051_added%2Banswers%2Bjson.jpg" alt="" loading="lazy" width="880" height="335"></a></p> <h2> <a name="adding-new-answers" href="#adding-new-answers"> </a> Adding New Answers </h2> <p>We will repeat the same method as we did with our Upload <code>Question</code> functionality for the add answer functionality, but with a minor difference. In your <code>Displayforum</code> component, add the following code:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import axios from "axios"; ... const [answer, setAnswer] = useState("") const [id, setId] = useState(""); const [a, formerArray] = useState([]); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We will store the input from the <code>textarea</code> in <code>answer</code>. We will use the <code>id</code> variable to reference the collection we want to add the answer to.</p> <p>Then in our form <code>textarea</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <textarea type="text" placeholder="Enter your answer" rows="5" value={answer} onChange={(e) => setAnswer(e.target.value)} /> <button onClick={() => { setId(response.id); formerArray(response.Answers); submitAnswer() }}>Post</button> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then in the <code>submitAnswer</code> function:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> const submitAnswer = () => { try { axios.put(`http://localhost:1337/forums/${id}`, { Answers: [...a, answer], }); } catch (error) { console.log(error); } }; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>With this, we can now add answers through our form to our collection.</p> <h2> <a name="user-authentication-with-nextauth" href="#user-authentication-with-nextauth"> </a> User Authentication with NextAuth </h2> <p>This section will use <a href="https://next-auth.js.org/">Nextauth</a>, a NextJs package for authentication, to implement Google login for our application. We will also set up protected routes so that only authenticated users can create questions and view them.</p> <p>To install <code>next-auth</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code> npm i next-auth </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>For our authentication, we will make use of <a href="https://jwt.io/introduction">JWT token</a> . JWT is a standard used to create access tokens for an application.</p> <p>We will create a file to handle user authentication. To do this, create a folder named <code>auth</code> in your <code>api</code> folder and within it, create a file <code>[...nextauth].js</code> with the following code in it:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import NextAuth from "next-auth"; import GoogleProvider from 'next-auth/providers/google' export default NextAuth({ providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth?prompt=consent&access_type=offline&response_type=code', }) ], jwt: { encryption: true }, secret: process.env.secret, callbacks: { async jwt(token, account) { if (account ?.accessToken) { token.accessToken = account.accessToken } return token; }, redirect: async (url, _baseUrl)=>{ if (url === '/check') { return Promise.resolve('/') } return Promise.resolve('/') } } }); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>The code above sets up our <code>Google Authentication</code> for our app. To use it, we need to wrap up our application in <code>_app.js</code> with the Google Provider component:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... import {Provider} from 'next-auth/client' function MyApp({ Component, pageProps }) { return ( <Provider session={pageProps.session}> <Component {...pageProps} /> </Provider> ); } export default MyApp; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Next, we will modify our <code>Displayforum</code> component in to return to our component if the user is authenticated, else it returns a button that leads to an authentication page:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import {signIn, signOut, useSession} from 'next-auth/client' ... const [session, loadingSession] = useSession(); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We will use <code>useSession</code> to know if our user has been authorized.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> if (loadingSession) { <> <p>logging in</p> </>; } return( ... </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>The above code simply returns “logging in” if <code>loadingSession</code> is true. If there is <code>session</code>, we will return the rest of the component and if there is no <code>session</code> we will render a button to <code>sign in</code> to access the app.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> return( <div> {!session && ( <> <h1>Sign in to access forum</h1> <button onClick={() => signIn()}>Sign In</button> </> )} {session && ( <> {/*rest of our app*/} </> )} </div> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We will also set our button to <code>Sign out</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... <Link href="/upload"> <button>Ask a question</button> </Link> <button onClick={() => signOut()}>Signout</button> ... </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>To make use of <code>Google authentication</code> in our app, we will require access credentials from Google Cloud console. To get this, navigate in your browser to <a href="https://console.developers.google.com/apis/credentials.">Google Cloud</a>.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8fyVQQWR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635626385264_create%2Bkey.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8fyVQQWR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635626385264_create%2Bkey.jpg" alt="" loading="lazy" width="488" height="309"></a></p> <p>Click on <code>OAuth Client ID</code> and Fill out the fields on the new page that opens.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jdbKsofe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635626440061_create%2Bkey2.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jdbKsofe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635626440061_create%2Bkey2.jpg" alt="" loading="lazy" width="880" height="455"></a></p> <p>Finally, set the redirect URL to: <a href="http://localhost/api/auth/callback/google">http://localhost/api/auth/callback/google</a></p> <p>To use the credentials in the <code>[…nextauth].js</code> file, you can create a <code>.env</code> file and set up your environmental variables:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> GOOGLE_CLIENT_ID: id GOOGLE_CLIENT_SECRET: secret secret: any string </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Next, we will set up our <code>Uploadforum.js</code> component on our <code>upload</code> page as a protected route so that unauthorized users can’t access the route. To do this, in <code>upload.js</code> add the following code:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { getSession, useSession } from 'next-auth/client' </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then at the bottom:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> export async function getServerSideProps(context) { const session = await getSession(context); if (!session) { context.res.writeHead(302, { Location: '/' }); context.res.end(); return {}; } return { props: { user: session.user, } } } export default Upload; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Now, if you run the app with <code>npm run dev</code> in CLI, we have <code>Google authentication</code> implemented. Also we can’t access the <code>/upload</code> path without logging in.</p> <h2> <a name="adding-user-name-to-collection" href="#adding-user-name-to-collection"> </a> Adding User name to Collection </h2> <p>Now that we have added authentication to our app, we can add the <code>username</code> received from the <code>Google Login</code> as the <code>Answername</code> field when we answer a question:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... axios.put(`http://localhost:1337/forums/${id}`, { Answers: [...a, answer], Answername: session.user.name, }); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Now, if I add a new answer to the form:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lnTi91zI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635629050599_before%2Bpost.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lnTi91zI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635629050599_before%2Bpost.jpg" alt="" loading="lazy" width="880" height="272"></a></p> <p>When I click on the <code>Post</code> button, I get:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DOQyNCJQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635629083784_After%2Bsubmission.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DOQyNCJQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635629083784_After%2Bsubmission.jpg" alt="" loading="lazy" width="880" height="169"></a></p> <p>The answer has been added and the <code>Answername</code> field has been set to my <code>user.name</code> form our <code>session</code>.</p> <p>Finally, we will also add the <code>username</code> when posting a question to our <code>collection</code>. We will do this in our <code>upload.js</code> file:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> const [session, loadingSession] = useSession(); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then we pass the value of <code>session</code> to our <code>Uploadforum</code> Component:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <Uploadforum session={session} /> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can now use <code>session</code> data in our <code>Uploadforum</code> component:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> function Uploadforum({session}) { ... const newQuestion = { Title: name, Questions: description, Answers: [""], Username: session.user.name, }; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Any new questions added now take the <code>Username</code> field to be the <code>username</code> received from <code>session</code>.</p> <p>If we add new answers, since the <code>Answername</code> is a field, it overwrites the previous data and all the <code>answers</code> use the same name. To fix this, we will simply modify our <code>Answers</code> field of type JSON to contain both the answers and the username of the person providing the answers.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XNbqg2mj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635678809482_compounded%2Banswers%2Band%2Busername.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XNbqg2mj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635678809482_compounded%2Banswers%2Band%2Busername.jpg" alt="" loading="lazy" width="880" height="406"></a></p> <p>Then, we can get this data and display it in our <code>Displayforum</code> component:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <div className={style.answers}> {response.Answers.map((answers, i) => ( <div className={style.eachanswer} key={i}> <p className={style.username}>{answers[0]}</p> <p className={style.answertext}>{answers[1]}</p> </div> ))} </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p><code>answer[0]</code> is the name of the user, while <code>answers[1]</code> is the answer.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gkFoOjyL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679166354_compounded%2Banswers%2B.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gkFoOjyL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679166354_compounded%2Banswers%2B.jpg" alt="" loading="lazy" width="880" height="339"></a></p> <p>Finally, we will modify the code to add new answers:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... axios.put(`http://localhost:1337/forums/${id}`, { Answers: [...a, [session.user.name, answer]], }); } catch (error) { console.log(error); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can now add new answers to our questions without overwriting previous data.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g5whN-Z9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679343611_final%2Btest.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g5whN-Z9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679343611_final%2Btest.jpg" alt="" loading="lazy" width="880" height="453"></a></p> <p>When I click on post I get a new answer:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KEWj1FXK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679382631_final%2Bresult.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KEWj1FXK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679382631_final%2Bresult.jpg" alt="" loading="lazy" width="880" height="478"></a></p> <h2> <a name="conclusion" href="#conclusion"> </a> Conclusion </h2> <p>We have come to the end of this tutorial. In this tutorial, we learned how to use Strapi CMS and connect it to NextJ's front-end. In this process, we built a forum site and implemented user authentication and authorization on it.</p> <h2> <a name="resources" href="#resources"> </a> Resources </h2> <p>The source code used in this tutorial can be found in the GitHub repo: <a href="https://github.com/Victory-ET/Strapi-Forumapp">Forum Application</a>.</p>
import React, { useState } from "react"; import style from "../../styles/Home.module.css"; import Link from "next/link"; function Displayforum() { const [show, setShow] = useState(false); return ( Display forum Ask a question Login Questions Posted By: Victory Tuduo Description of the Question Answers Post setShow(!show)}> {show ? "Hide Answers" : "Show Answers"} {show ? (
) : null} ); } export default Displayforum;Miracle
Try doing it Like this
Enter fullscreen mode Exit fullscreen modeThis component handles the layout of our display forum page. We also have a button here that directs the user to the page to upload new questions.
Meanwhile, in
upload.js
we have the following:
import React from "react"; import Uploadforum from "./Components/Uploadforum"; function upload() { return (
); } export default upload;Enter fullscreen mode Exit fullscreen modeHere, we simply added an import for the
Uploadforum
component into our page. InUploadforum.js
file we have a simple form to create new questions:
import React from "react"; import style from "../../styles/Home.module.css"; import Link from "next/Link"; function Uploadforum() { return (
Ask a question
Forum<button>Submit Question</button> </form> </div> </div> ); } export default Uploadforum; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Finally, we have the following styles in <code>Home.module.css</code><br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> .container { min-height: 100vh; padding: 0 0.5rem; height: 100vh; font-family: monospace; } /* display forum page */ .topcont { display: flex; justify-content: space-between; align-items: center; padding: 5px 8px; } .topcont button, .inputanswer button, .formcont button, .showanswer { border: none; color: #fff; background: dodgerblue; border-radius: 8px; padding: 10px 15px; outline: none; margin: 8px; } .topcont button:hover { cursor: pointer; transform: scale(1.2); } .heading { font-weight: bold; } .subheading { font-weight: 500; text-transform: uppercase; } .userinfo { font-size: 18px; font-weight: 600; } .questioncont { min-height: 300px; padding: 15px 14px; box-shadow: 12px 12px 36px rgba(0, 0, 0, 0.12); } .answercont { min-height: 300px; padding: 5px 3px 5px 15px; } .answers { height: 300px; overflow-x: scroll; } .inputanswer { margin-bottom: 8px; } .inputanswer textarea { width: 100%; resize: none; padding: 5px 8px; } .showanswer { border: 1px solid dodgerblue; background: #fff; color: dodgerblue; transition: 0.4s ease-in-out; } .showanswer:hover { background: dodgerblue; color: #fff; } .eachanswer { border-radius: 15px; background: #e7e7e7; padding: 8px 15px; margin-bottom: 10px; } .username { font-weight: bold; text-transform: uppercase; } .answertext { font-family: Montserrat; font-size: 14px; font-weight: 500; } /* upload a question page */ .uploadpage { min-height: 100vh; } .formcont { min-width: 100vw; display: flex; justify-content: center; align-items: center; } .uploadform { display: flex; flex-direction: column; min-width: 500px; padding-top: 10px; } .uploadform input, .uploadform textarea { resize: none; width: 100%; margin: 8px; padding: 5px; } </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>All of this makes up the layout of our pages.</p> <h2> <a name="getting-data-from-strapi" href="#getting-data-from-strapi"> </a> Getting data from Strapi: </h2> <h2> <a name="setting-up-our-fetch-request" href="#setting-up-our-fetch-request"> </a> Setting up our Fetch Request </h2> <p>In this section, we will fetch our data from Strapi and display it in our app. We will be using <a href="https://axios-http.com/docs/intro">Axios</a> to perform our fetch operations.</p> <p>We will install this via CLI:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code> npm <span class="nb">install </span>axios </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Create a file <code>index.js</code> in the API folder. Here, we will set up our fetch request:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import axios from "axios"; const url = "http://localhost:1337/strapi-forums"; export const readForum = () => axios.get(url); export const createQuestion = (newQuestion) => axios.post(url, newQuestion); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Above, we added import for <code>axios</code>, the URL to fetch our data, and exported functions to read and create data from our forum.</p> <p>We’ll import these functions into our app in our <code>index.js</code> file:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { readForum, createQuestion } from "./api"; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <h2> <a name="fetching-data-from-strapi" href="#fetching-data-from-strapi"> </a> Fetching Data from Strapi </h2> <p>We will fetch the data from Strapi in our <code>index.js</code> file and pass it to <code>Displayforum.js</code> component to display it:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { react, useState, useEffect } from "react"; ... const [question, setQuestions] = useState({}); const [response, setResponse] = useState([]); useEffect(() => { const fetchData = async () => { const result = await readForum(); setResponse(result.data); }; fetchData(); }, []); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Here, we fetched our data from Strapi and assigned it to <code>response</code> with the React <code>useState</code> hook. We have a <code>useEffect</code> function that makes the request when our component mounts.</p> <p>Now, we pass this <code>response</code> down to our <code>Displayforum</code> component.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <Displayforum response={response} /> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <h2> <a name="displaying-data-from-strap" href="#displaying-data-from-strap"> </a> Displaying Data from Strap </h2> <p>To display our data in our <code>Displayforum.js</code> file, we will map our responses and render our components. Before we do this, we will create two additional text fields in our Strapi CollectionCollection: <code>Username</code> and <code>Answername</code>.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c2XelJbV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635543765246_created%2Bnew%2Bfields.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c2XelJbV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635543765246_created%2Bnew%2Bfields.jpg" alt="" loading="lazy" width="792" height="468"></a></p> <p>Back in our <code>Displayforum</code> component we will proceed with displaying our data:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... function Displayforum({ response }) { ... {response.map((response, index) => ( <div key={index}> <div className={style.userinfo}> ... <p className={style.answertext}>Try doing it Like this</p> </div> </div> ) : null} </div> </div> ))} </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Here, we wrapped up our components to map through <code>response</code> and display this component as many times as the number of responses. To display our Strapi data, we simply reference it. We can get our <code>Username</code> with this code:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> response.Username </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can now add this to our component and display it:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <p>Posted By: {response.Username}</p> ... <p className={style.question}>{response.Questions}</p> ... <p className={style.username}>{response.Answername}</p> <p className={style.answertext}>{response.Answers}</p> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We have successfully added the data from our CollectionCollection to our <code>front-end</code> to view this in the browser. Run the following command in the CLI:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code> npm run dev </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>In your browser, you will have an output similar to the image below:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0X_EJPA4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635545169076_got%2Bdata%2Bfrom%2BStrapi.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0X_EJPA4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635545169076_got%2Bdata%2Bfrom%2BStrapi.jpg" alt="" loading="lazy" width="880" height="399"></a></p> <p>After this, we will add functionality to add new questions to Strapi.</p> <h2> <a name="adding-data-to-strapi" href="#adding-data-to-strapi"> </a> Adding data to Strapi </h2> <p>In our <code>Uploadforum.js</code> file, we will add functionality to upload the contents of the form to Strapi. First, we will create two state variables to store the text from our <code>inputs</code>.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { React, useState } from "react"; ... const [name, setName] = useState(""); const [description, setDescription] = useState(""); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then we set these variables to the value of our form <code>input</code>.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <input type="text" placeholder="Enter your title" maxLength="74" value={name} onChange={(e) => setName(e.target.value)} /> <textarea type="text" placeholder="Enter your description" rows="8" value={description} onChange={(e) => setDescription(e.target.value)} /> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Also we will a function to send these variables when we click our <code>button</code>.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <button onClick={() => sendData()}>Submit Question</button> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can create the <code>sendData</code> function above our <code>return</code>.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> const sendData = () => { }; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>For our create functionality we will import the <code>createQuestion</code> function we defined in our <code>api</code> folder.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { createQuestion } from "../api"; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then we pass in our data to this function.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> const sendData = () => { const newQuestion = { Title: name, Questions: description, }; createQuestion(newQuestion); }; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can now upload new questions to our Strapi <code>collection</code>. We will add the <code>Username</code> when we cover user authentication.</p> <p>Next up, we will add functionality to answer questions in our <code>Displayforum</code> component.</p> <h2> <a name="adding-functionality-to-answer-questions" href="#adding-functionality-to-answer-questions"> </a> Adding Functionality to Answer Questions </h2> <p>Since we set a text field for our answers in our <code>collection</code>, it can only take in one value. To have multiple answers for a question, we will delete the Answers field and create another field for our Answers of type <code>json</code>.</p> <p>With that done, here is an example of what a response from our API would look like:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6ji2Py_9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635601446784_new%2Bresponse.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6ji2Py_9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635601446784_new%2Bresponse.jpg" alt="" loading="lazy" width="586" height="423"></a></p> <p>To display our answers, we will map through <code>Answers</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> {response.Answers.map((answers, i) => ( <div className={style.eachanswer} key={i}> <p className={style.username}>{response.Answername}</p> <p className={style.answertext}>{answers}</p> </div> ))} </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Now in our browser, if we add more <code>answers</code> to our JSON collection, we can see them displayed on our page.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jt0sMsr0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635602131051_added%2Banswers%2Bjson.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jt0sMsr0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635602131051_added%2Banswers%2Bjson.jpg" alt="" loading="lazy" width="880" height="335"></a></p> <h2> <a name="adding-new-answers" href="#adding-new-answers"> </a> Adding New Answers </h2> <p>We will repeat the same method as we did with our Upload <code>Question</code> functionality for the add answer functionality, but with a minor difference. In your <code>Displayforum</code> component, add the following code:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import axios from "axios"; ... const [answer, setAnswer] = useState("") const [id, setId] = useState(""); const [a, formerArray] = useState([]); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We will store the input from the <code>textarea</code> in <code>answer</code>. We will use the <code>id</code> variable to reference the collection we want to add the answer to.</p> <p>Then in our form <code>textarea</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <textarea type="text" placeholder="Enter your answer" rows="5" value={answer} onChange={(e) => setAnswer(e.target.value)} /> <button onClick={() => { setId(response.id); formerArray(response.Answers); submitAnswer() }}>Post</button> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then in the <code>submitAnswer</code> function:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> const submitAnswer = () => { try { axios.put(`http://localhost:1337/forums/${id}`, { Answers: [...a, answer], }); } catch (error) { console.log(error); } }; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>With this, we can now add answers through our form to our collection.</p> <h2> <a name="user-authentication-with-nextauth" href="#user-authentication-with-nextauth"> </a> User Authentication with NextAuth </h2> <p>This section will use <a href="https://next-auth.js.org/">Nextauth</a>, a NextJs package for authentication, to implement Google login for our application. We will also set up protected routes so that only authenticated users can create questions and view them.</p> <p>To install <code>next-auth</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code> npm i next-auth </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>For our authentication, we will make use of <a href="https://jwt.io/introduction">JWT token</a> . JWT is a standard used to create access tokens for an application.</p> <p>We will create a file to handle user authentication. To do this, create a folder named <code>auth</code> in your <code>api</code> folder and within it, create a file <code>[...nextauth].js</code> with the following code in it:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import NextAuth from "next-auth"; import GoogleProvider from 'next-auth/providers/google' export default NextAuth({ providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth?prompt=consent&access_type=offline&response_type=code', }) ], jwt: { encryption: true }, secret: process.env.secret, callbacks: { async jwt(token, account) { if (account ?.accessToken) { token.accessToken = account.accessToken } return token; }, redirect: async (url, _baseUrl)=>{ if (url === '/check') { return Promise.resolve('/') } return Promise.resolve('/') } } }); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>The code above sets up our <code>Google Authentication</code> for our app. To use it, we need to wrap up our application in <code>_app.js</code> with the Google Provider component:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... import {Provider} from 'next-auth/client' function MyApp({ Component, pageProps }) { return ( <Provider session={pageProps.session}> <Component {...pageProps} /> </Provider> ); } export default MyApp; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Next, we will modify our <code>Displayforum</code> component in to return to our component if the user is authenticated, else it returns a button that leads to an authentication page:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import {signIn, signOut, useSession} from 'next-auth/client' ... const [session, loadingSession] = useSession(); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We will use <code>useSession</code> to know if our user has been authorized.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> if (loadingSession) { <> <p>logging in</p> </>; } return( ... </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>The above code simply returns “logging in” if <code>loadingSession</code> is true. If there is <code>session</code>, we will return the rest of the component and if there is no <code>session</code> we will render a button to <code>sign in</code> to access the app.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> return( <div> {!session && ( <> <h1>Sign in to access forum</h1> <button onClick={() => signIn()}>Sign In</button> </> )} {session && ( <> {/*rest of our app*/} </> )} </div> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We will also set our button to <code>Sign out</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... <Link href="/upload"> <button>Ask a question</button> </Link> <button onClick={() => signOut()}>Signout</button> ... </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>To make use of <code>Google authentication</code> in our app, we will require access credentials from Google Cloud console. To get this, navigate in your browser to <a href="https://console.developers.google.com/apis/credentials.">Google Cloud</a>.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8fyVQQWR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635626385264_create%2Bkey.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8fyVQQWR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635626385264_create%2Bkey.jpg" alt="" loading="lazy" width="488" height="309"></a></p> <p>Click on <code>OAuth Client ID</code> and Fill out the fields on the new page that opens.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jdbKsofe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635626440061_create%2Bkey2.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jdbKsofe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635626440061_create%2Bkey2.jpg" alt="" loading="lazy" width="880" height="455"></a></p> <p>Finally, set the redirect URL to: <a href="http://localhost/api/auth/callback/google">http://localhost/api/auth/callback/google</a></p> <p>To use the credentials in the <code>[…nextauth].js</code> file, you can create a <code>.env</code> file and set up your environmental variables:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> GOOGLE_CLIENT_ID: id GOOGLE_CLIENT_SECRET: secret secret: any string </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Next, we will set up our <code>Uploadforum.js</code> component on our <code>upload</code> page as a protected route so that unauthorized users can’t access the route. To do this, in <code>upload.js</code> add the following code:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { getSession, useSession } from 'next-auth/client' </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then at the bottom:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> export async function getServerSideProps(context) { const session = await getSession(context); if (!session) { context.res.writeHead(302, { Location: '/' }); context.res.end(); return {}; } return { props: { user: session.user, } } } export default Upload; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Now, if you run the app with <code>npm run dev</code> in CLI, we have <code>Google authentication</code> implemented. Also we can’t access the <code>/upload</code> path without logging in.</p> <h2> <a name="adding-user-name-to-collection" href="#adding-user-name-to-collection"> </a> Adding User name to Collection </h2> <p>Now that we have added authentication to our app, we can add the <code>username</code> received from the <code>Google Login</code> as the <code>Answername</code> field when we answer a question:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... axios.put(`http://localhost:1337/forums/${id}`, { Answers: [...a, answer], Answername: session.user.name, }); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Now, if I add a new answer to the form:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lnTi91zI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635629050599_before%2Bpost.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lnTi91zI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635629050599_before%2Bpost.jpg" alt="" loading="lazy" width="880" height="272"></a></p> <p>When I click on the <code>Post</code> button, I get:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DOQyNCJQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635629083784_After%2Bsubmission.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DOQyNCJQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635629083784_After%2Bsubmission.jpg" alt="" loading="lazy" width="880" height="169"></a></p> <p>The answer has been added and the <code>Answername</code> field has been set to my <code>user.name</code> form our <code>session</code>.</p> <p>Finally, we will also add the <code>username</code> when posting a question to our <code>collection</code>. We will do this in our <code>upload.js</code> file:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> const [session, loadingSession] = useSession(); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then we pass the value of <code>session</code> to our <code>Uploadforum</code> Component:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <Uploadforum session={session} /> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can now use <code>session</code> data in our <code>Uploadforum</code> component:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> function Uploadforum({session}) { ... const newQuestion = { Title: name, Questions: description, Answers: [""], Username: session.user.name, }; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Any new questions added now take the <code>Username</code> field to be the <code>username</code> received from <code>session</code>.</p> <p>If we add new answers, since the <code>Answername</code> is a field, it overwrites the previous data and all the <code>answers</code> use the same name. To fix this, we will simply modify our <code>Answers</code> field of type JSON to contain both the answers and the username of the person providing the answers.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XNbqg2mj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635678809482_compounded%2Banswers%2Band%2Busername.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XNbqg2mj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635678809482_compounded%2Banswers%2Band%2Busername.jpg" alt="" loading="lazy" width="880" height="406"></a></p> <p>Then, we can get this data and display it in our <code>Displayforum</code> component:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <div className={style.answers}> {response.Answers.map((answers, i) => ( <div className={style.eachanswer} key={i}> <p className={style.username}>{answers[0]}</p> <p className={style.answertext}>{answers[1]}</p> </div> ))} </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p><code>answer[0]</code> is the name of the user, while <code>answers[1]</code> is the answer.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gkFoOjyL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679166354_compounded%2Banswers%2B.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gkFoOjyL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679166354_compounded%2Banswers%2B.jpg" alt="" loading="lazy" width="880" height="339"></a></p> <p>Finally, we will modify the code to add new answers:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... axios.put(`http://localhost:1337/forums/${id}`, { Answers: [...a, [session.user.name, answer]], }); } catch (error) { console.log(error); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can now add new answers to our questions without overwriting previous data.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g5whN-Z9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679343611_final%2Btest.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g5whN-Z9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679343611_final%2Btest.jpg" alt="" loading="lazy" width="880" height="453"></a></p> <p>When I click on post I get a new answer:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KEWj1FXK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679382631_final%2Bresult.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KEWj1FXK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679382631_final%2Bresult.jpg" alt="" loading="lazy" width="880" height="478"></a></p> <h2> <a name="conclusion" href="#conclusion"> </a> Conclusion </h2> <p>We have come to the end of this tutorial. In this tutorial, we learned how to use Strapi CMS and connect it to NextJ's front-end. In this process, we built a forum site and implemented user authentication and authorization on it.</p> <h2> <a name="resources" href="#resources"> </a> Resources </h2> <p>The source code used in this tutorial can be found in the GitHub repo: <a href="https://github.com/Victory-ET/Strapi-Forumapp">Forum Application</a>.</p>