Table of Contents
ToggleIntroduction
If you’re eager to create some impressive real-world apps using Next.js, you’re in for a treat. Whether you’re interested in creating a recipe finder app, setting up your e-commerce store, or creating a portfolio blog to showcase your talent, Next.js is a go-to solution that offers the tools and flexibility. Its versatile nature can bring life to your fresh ideas in your projects and is ideal for beginners. This article walks you through beginner-friendly projects to grasp the fundamentals and enhance your skills. Let’s jump straight into it!
Create a Quiz Using Next.js
- First, you need to set up your account on the Butter CMS from the following link and create your account.
- Once done, navigate to the left side menu and click on the “collection” option. This will create a field for the quiz including questions, available options, correct options, and correct answers containing explanations.
- Go to the collection page and click the “New Item” button. Then create a collection as “my quiz app” with the names of the fields mentioned in the second step.
- After that, you will be directed to the new page to fill in all questions, correct answers, options, and explanations.
- When you’re done with it, click “Publish” button and then add one more additional field.
- Next, you need to install the dependencies so open your command line interface and add the following code. It will create a new Next.js app as “quizapp” npx create-next-app quizapp
- You will need to perform an API request so write the following command:
npm install axios.
- To style your app, add the following command, this will install Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init –p - Once installed, open your app directory from your preferred code editor and then add the code to your tailwind.config.js file:
@type {import('tailwindcss').Config}
module.exports = {
content: [
“./pages/**/*.{js,ts,jsx,tsx}”,
“./components/**/*.{js,ts,jsx,tsx}”,
],
theme: {
extend: {},
},
plugins: [],
By following these step you will have installed all the required dependencies and necessary tools to create a quiz app in Next.js. Your quiz app will now consist of a landing page with the option to begin the quiz and a page containing questions for users. The next section walks you through the code to build the front end for your app.
Code to Create the Front-end of the Quiz Application
Open the index.js file and add the following code:
import React from "react"
import Quizselection from "../components/Quizselection"
export default function Home() {
return (
<div>
<Quizselection/>
</div>
)
The above code defines a simple React component as home which imports another component “Quizselection” and renders it with a div element as a part of the user interface.
Read more- What is Next.js? And What it is Used for?
Code to Create a Quiz Selection Page
- Create a folder as a component in your project directory first.
- Inside the component folder create a new file “Quizselection.jsx” file and the add following code:
import { React } from "react";
import Link from "next/link";
const Quizselection = () => {
return (
<div className=" pt-6">
<h1 className=" text-blue-700 text-center text-3xl font-medium my-6 ">
Welcome to my Quiz App
</h1>
<p className=" text-center mt-12 mb-8 ">
Looking to test your general knowledge..? Then you are at the right
place. Try out this fun quiz!
</p>
<div className=" flex justify-center items-center">
<div className=" w-[500px] px-8 py-4 shadow-2xl bg-blue-400 text-white flex justify-center items-center flex-col gap-6 ">
<h1 className=" font-extrabold text-xl ">A Fun Quiz</h1>
<p>
A quiz covering different areas of general knowledge. Test your
knowledge and see how much you know as you go along. Answer
questions on history, geography, science, movies, and more.
</p>
<div className="w-full flex justify-end pr-3">
<button className=" bg-white px-5 py-2 rounded-sm text-black hover:cursor-pointer ">
<Link href="/test" >Begin Quiz</Link>
</button>
</div>
</div>
</div>
</div>
);
};
export default Quizselection;
This code uses HTML-like and JSX styling classes from Tailwind CSS and link components to enable smooth navigation within the application. And displays the selection page with the button to begin the quiz.
Code to Display Quiz Question
- Create a new folder test to organize all the files related to the test page and display them to the user.
- Now add the following code and then run it using this command “npm run dev”
import { React, useState, useEffect } from "react";
import Link from "next/link";
const Index = () => {
const [isQuestionAnswered, setIsQuestionAnswered] = useState(false);
return (
<div className="h-screen w-full flex justify-center items-center ">
<div className="w-4/5 h-3/4 shadow-2xl flex flex-col justify-center items-center font-medium gap-16 ">
<h1 className="text-2xl">What is the capital of England?</h1>
<div className=" grid grid-cols-2 gap-8 gap-x-12 ">
{/* options */}
<div className=" w-[400px] rounded-md flex justify-center items-center py-4 text-white bg-blue-400 hover:cursor-pointer hover:bg-blue-600">
Spain
</div>
<div className=" w-[400px] rounded-md flex justify-center items-center py-4 text-white bg-blue-400 hover:cursor-pointer hover:bg-blue-600">
Spain
</div>
<div className=" w-[400px] rounded-md flex justify-center items-center py-4 text-white bg-blue-400 hover:cursor-pointer hover:bg-blue-600">
Spain
</div>
<div className=" w-[400px] rounded-md flex justify-center items-center py-4 text-white bg-blue-400 hover:cursor-pointer hover:bg-blue-600">
Spain
</div>
</div>
{isQuestionAnswered? (
<div className=" w-full px-2 ">
<p className=" max-h-[100px] overflow-y-scroll ">
{/* correct answer explanation here */}
</p>
</div>
):null}
</div>
</div>
);
};
export default Index;
This code displays the single quiz question with multiple options with the use of “useState”. It uses conditional rendering based on the value that users use it displays the answer section. The component structure is designed to be reused for various quiz questions within the applications.
Don't miss out on your chance to work with the best!
Apply for top job opportunities today!
Steps to Connect App to ButterCMS
- First, you need to locate the Read API token to authenticate and fetch the content from ButterCMS.
- After that, create a file name “.env” to store the environment variable as REACT_APP_READ_TOKEN. Make the same changes within the test folder of the index.js file.
- Now add the following code to fetch requests to your quiz app.
import axios from "axios";
const Index = () => {
const [isQuestionAnswered, setIsQuestionAnswered] = useState(false);
const [questionLength, setQuestionLength] = useState(0);
const [questionNumber, setQuestionNumber] = useState(0);
const [totalScore, setTotalScore] = useState(0);
const [quizQuestions, setQuizQuestions] = useState([]);
const read_token = process.env.REACT_APP_READ_TOKEN;
useEffect(() => {
const fetchData = async () => {
const result = await axios(
`https://api.buttercms.com/v2/content/my_quiz_app?auth_token=${read_token}`
);
setQuizQuestions(result.data.data.my_quiz_app);
setQuestionLength(result.data.data.my_quiz_app.length);
};
fetchData()
}, []);
In this code, we added, states for a score, a number for the current question, and a length. Then this code fetch request from an external API, sets up the necessary states to manage quiz functionality, and handles the data for further processing.
Now, add the following code to read data from ButterCMS.
<h1 className="text-2xl">{quizQuestions[questionNumber]?.quiz_question}?</h1>
<div className=" grid grid-cols-2 gap-8 gap-x-12 ">
{/* options */}
<div className=" w-[400px] rounded-md flex justify-center items-center py-4 text-white bg-blue-400 hover:cursor-pointer hover:bg-blue-600">
{quizQuestions[questionNumber]?.option_one}
</div>
<div className=" w-[400px] rounded-md flex justify-center items-center py-4 text-white bg-blue-400 hover:cursor-pointer hover:bg-blue-600">
{quizQuestions[questionNumber]?.option_two}
</div>
<div className=" w-[400px] rounded-md flex justify-center items-center py-4 text-white bg-blue-400 hover:cursor-pointer hover:bg-blue-600">
{quizQuestions[questionNumber]?.option_three}
</div>
<div className=" w-[400px] rounded-md flex justify-center items-center py-4 text-white bg-blue-400 hover:cursor-pointer hover:bg-blue-600">
{quizQuestions[questionNumber]?.option_four}
</div>
</div>
{isQuestionAnswered ? (
<div className=" w-full px-2 ">
<p className=" max-h-[100px] overflow-y-scroll ">
{/* correct answer explanation here */}
{quizQuestions[questionNumber]?.explanation}
</p>
</div>
) : null}
Add the following code to add a feature in the user answer choice:
<div className=" w-[400px] rounded-md flex justify-center items-center py-4 text-white bg-blue-400 hover:cursor-pointer hover:bg-blue-600" onClick={()=>handleChoice(quizQuestions[questionNumber]?.option_one)} >
{quizQuestions[questionNumber]?.option_one}
</div>
<div className=” w-[400px] rounded-md flex justify-center items-center py-4 text-white bg-blue-400 hover:cursor-pointer hover:bg-blue-600″ onClick={()=>handleChoice(quizQuestions[questionNumber]?.option_two)} >
{quizQuestions[questionNumber]?.option_two}
</div>
<div className=” w-[400px] rounded-md flex justify-center items-center py-4 text-white bg-blue-400 hover:cursor-pointer hover:bg-blue-600″ onClick={()=>handleChoice(quizQuestions[questionNumber]?.option_three)} >
{quizQuestions[questionNumber]?.option_three}
</div>
<div className=” w-[400px] rounded-md flex justify-center items-center py-4 text-white bg-blue-400 hover:cursor-pointer hover:bg-blue-600″ onClick={()=>handleChoice(quizQuestions[questionNumber]?.option_four)} >
{quizQuestions[questionNumber]?.option_four}
</div>
const handleChoice = (choice) => {
if (choice === quizQuestions[questionNumber]?.correct_option && !isQuestionAnswered) {
setIsQuestionAnswered(true);
setTotalScore(totalScore + 1);
alert(“You got it correctly”);
} else if (choice !== quizQuestions[questionNumber]?.correct_option && !isQuestionAnswered) {
setIsQuestionAnswered(true);
alert(“Oops, you got it wrong”);
}
else{
alert(“You have already answered this question”);
}
};
//return statement below
{isQuestionAnswered? (<button className=” bg-gray-900 px-3 py-2 w-max text-white ” onClick={()=>{
setQuestionNumber(questionNumber+1)
setIsQuestionAnswered(false)
}} >NextQuestion</button>):null}
In the above code, we have added four options with the “onClick” handler. We have added the “handleChoice()” function to the click event handler to pass the option that the user selected as an argument to it. Whenever users select the option the explanation is revealed with a right or wrong response. Lastly, it will check whether the question is answered or not, if the statement returns true, it will increase the value of the question state by 1. That means it will take a quiz to the next question by hiding the explanation.
Code to End the Quiz with Score
const [quizEnded, setQuizEnded] = useState(false);
<>
<div className="h-screen w-full flex justify-center items-center ">
{!quizEnded ? (
// quiz code block here
) : (
<div className="w-4/5 min-h-[75%] shadow-2xl flex flex-col justify-center items-center font-medium gap-16 ">
<h1>Hurray, you have completed the quiz!</h1>
<h1 className="text-2xl">Your score is {totalScore} out of {questionLength}</h1>
<button
className=" bg-gray-900 px-3 py-2 w-max text-white "
onClick={() => {
setQuestionNumber(0);
setQuizEnded(false);
setTotalScore(0);
}}
>
Restart Quiz
</button>
<Link href="/" >Return to Home</Link>
</div>
)}
{isQuestionAnswered ? (
<button
className=" bg-gray-900 px-3 py-2 w-max text-white "
onClick={() => {
if (questionNumber + 1 === questionLength) {
setQuizEnded(true);
}
else{
setQuestionNumber(questionNumber + 1);
}
setIsQuestionAnswered(false);
}}
>
NextQuestion
</button>
) : null}
The code above takes the user to the end where no more questions are available and displays the end message with the final score. At last, users will have two buttons to either restart the quiz or return to the homepage.
Create an E-commerce Site using Next.js
- First, set up the development environment for Next.js using this command “npx create-next-app ecommerce-demo”
- A message will pop up to confirm the name of your project, once you confirm it’ll start to install the dependencies.
- Now you need to make your app available at localhost:3000.
- Once done, you need to define the layout as header and footer components.
- Create a components folder in the base folder to store all components together and add this code into the header file:
import Link from 'next/link';
import styles from '../styles/components/Header.module.css';
const Header = () =>
{
return (
<nav className={styles.navbar}>
<Link href="/">
<a>
<div className={styles.logo}>
<p>
Clothes <span className={styles.logo_span}></span>
</p>
</div>
</a>
</Link>
<div className={styles.nav_price}>
<span></span>
<p>$0.00</p>
</div>
</nav>
);
}; export default Header;
So by now, your header is ready, to create a footer file add the following code:
import styles from '../styles/components/Footer.module.css';
const Footer = () => {
return (
<footer className={styles.footer}>
<p>All Rights Reserved. Copyright © 2022</p>
</footer>
);
};
export default Footer;
Steps to Integrate Component into Layout
Create a layout component first and add this code for the component that takes children’s props, and then users can place them wherever they want.
import Header from './Header';
import Footer from ‘./Footer’;
const Layout = ({ children }) =>
{
return
(
<div>
<Header />
{children}
<Footer />
</div>
);
};
export default Layout;
import Layout from ‘../components/Layout’;
import ‘../styles/globals.css’;
function MyApp({ Component, pageProps }) {
return (
<>
<Layout>
<Component {…pageProps} />
</Layout>
</>
);
} export default MyApp;
This code will add the layout component and configure the app’s layout, you can launch the app layout and navigate to the localhost page. The next steps will walk you through creating an index page for your application.
Steps to Create an Index Page
- You must visit the repository to get the “products”, within the project, there is a folder “Page” that contains the subfolder “data” and inside the subfolder, there is an array of product data so from that you need to retrieve the JSON file.
- Go to the public directory and access the images folder within the “product.json” file.
- Add the following code to import the necessary module in the head component of the pages/index.js file “import allProducts from ‘./data/products.json‘;
import Head from ‘next/head‘;
import Link from ‘next/link‘;”
- Now, you need to import the CSS style to the component by adding the following code:
import styles from ‘../styles/Home.module.css‘;
- You need to define the default export function “Home” by taking the object “allProducts” as a prop by adding the code:
export default function Home({ allProducts })
{
return (
<>
<Head>
<title>Clothes| Home</title>
</Head>
<div className="container">
<h2 className={styles.title}>
All Products <span>Clothes</span>
</h2>
<div className={styles.products_container}>
{allProducts.map((product) => {
return (
<div className={styles.product_card} key={product.id}>
<Link href={`products/${product.slug}`}>
<a>
<div className={styles.product_img}>
<img src={product.image.url} alt={product.name} />
</div>
</a>
</Link>
<div className={styles.product_content}>
<h3>{product.name}</h3>
<p>${product.price}</p>
<button className="btn">Add to cart 🛒</button>
</div>
</div>
);
})}
</div>
</div>
</>
);
}
export async function getStaticProps() {
return {
props: {
allProducts,
},
};
}
This code defines the structure of component JSX and displays all products i.e., clothes, and maps through “allProducts” by generating the price, product name, and image for each item. The “getStaticProps” function is used to fetch data during the build time to ensure the availability of data while the page is rendered. Further, this function also enhances the performance of SEO.
Create a Developer Portfolio Blog
- First of all, you need to install Next.js with preconfigured Tailwind CSS:
npx create-next-app -e with-tailwindcss your-portfolio
- Now, create a component folder to use with every component of your Next.js app and add this folder as a path to the tsconfig.json file.
- Then add the baseURL and run this command to install dependencies in your project:
npm install
Steps to Create a Navigation Component
- Create a new file as “Navigation.tsx” within the components folder, which contains your name as a link.
- Now add the following code to create a header section for your portfolio.
import Link from "next/link"
import React from "react"
const Navigation = () => {
return (
<div className="sticky top-0 z-20 py-2 md:py-6 md:mb-6 dark:bg-black bg-white">
<div className="container px-4 mx-auto lg:max-w-4xl flex items-center justify-between">
<div className="items-start flex">
<Link href="/">
<a className={"font-medium tracking-wider transition-colors text-gray-900 dark:hover:text-sky-500 hover:text-sky-500 uppercase dark:text-white"}>
Paul Knulst
</a>
</Link>
</div>
</div>
</div>
)
}
export default Navigation
Now to make your navigation visible, you should edit your “_app.tsx” file and then add the following code
import '../styles/globals.css'
import type {AppProps} from 'next/app'
import Navigation from "@components/Navigation";
function MyApp({Component, pageProps}: AppProps) {
return (
<>
<Navigation/>
<Component {...pageProps} />
</>
)
}
export default MyApp
Steps to Create Footer
- Next, you need to create a “Footer.tsx” file within the component folder.
- Once done add the following code to add all of your social media account.
import React from “react”;const Footer = () => {
return (
<div className="mt-12 lg:mt-18 sm:pb-36 sm:py-12 py-6">
<div className="max-w-4xl px-4 mx-auto text-gray-800 dark:text-white">
<div className="pb-8 mb-2 border-t-2 border-gray-300 dark:border-white-300"/>
<div className="flex flex-col justify-between lg:flex-row items-center">
<p>Built with Next.js, Tailwind</p>
<div className="flex flex-wrap pt-2 sm:space-x-4 space-x-2 font-medium lg:pt-0">
<a
href="https://twitter.com/paulknulst"
className={"transition-colors hover:text-yellow-500"}
target="_blank"
rel="noreferrer"
>
Twitter
</a>
<a
href="https://www.linkedin.com/in/paulknulst/"
className={"transition-colors hover:text-yellow-500"}
target="_blank"
rel="noreferrer"
>
LinkedIn
</a>
<a
href="https://github.com/paulknulst"
className={"transition-colors hover:text-yellow-500"}
target="_blank"
rel="noreferrer"
>
GitHub
</a>
<a
href="https://blog.paulknulst.de"
className={"transition-colors hover:text-yellow-500"}
target="_blank"
rel="noreferrer"
>
</a>
</div>
</div>
</div>
</div>
)
}
export default Footer;
- After that, you need to add the footer component to the “_app.tsx” file, so add following:
import '../styles/globals.css'
import type {AppProps} from 'next/app'
import Navigation from "@components/Navigation";
import Footer from "@components/Footer";
function MyApp({Component, pageProps}) {
return <>
<Navigation/>
<Component {...pageProps} />
<Footer/>
</>
}
export default MyApp
Code to Create Homepage
import React from "react"
import Image from "next/image"
const Main = () => {
return (
<div className="container px-4 mx-auto">
<div
className="lg:space-x-5 lg:flex lg:flex-row item-center lg:-mx-4 flex flex-col-reverse text-center lg:text-left">
<div className="lg:px-4 lg:mt-12 ">
<h1 className="text-2xl font-bold text-gray-900 lg:text-5xl dark:text-white">
Hi there,
</h1>
<div className="mt-6 text-gray-800 dark:text-white">
<p className="mb-4">I am a Software Enginner <a
href="https://www.paulknulst.de"
className="font-bold transition-colors hover:text-sky-500" target="_blank"
rel="noopener">Link To Company</a>.
</p>
<p className="mb-4">Lorem Ipsum is simply dummy text of the printing and typesetting industry.
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an
unknown printer took a galley of type and scrambled it to make a type specimen book
</p>
<p className="mb-4">
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an
unknown printer took a galley of type and scrambled it to make a type specimen book
</p>
<h2 className="font-bold">I'm a rocket 🚀</h2>
</div>
</div>
<div className="flex-shrink-0 lg:mt-12 lg:px-4 mb-10">
<Image
src="https://picsum.photos/250/250"
alt="Profile"
priority={true}
className="rounded-full"
width={250}
height={250}
/>
<div className="flex justify-center mt-6">
<div
className="flex md:flex lg:flex sm:flex space-x-4 font-medium text-gray-800 sm:block dark:text-white">
<a className="transition-colors hover:text-sky-500" target="_blank" rel="noreferrer"
href="https://twitter.com/paulknulst">
<svg stroke="currentColor" fill="currentColor" strokeWidth="0" viewBox="0 0 448 512"
className="text-2xl" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
<path
d="M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48zm-48.9 158.8c.2 2.8.2 5.7.2 8.5 0 86.7-66 186.6-186.6 186.6-37.2 0-71.7-10.8-100.7-29.4 5.3.6 10.4.8 15.8.8 30.7 0 58.9-10.4 81.4-28-28.8-.6-53-19.5-61.3-45.5 10.1 1.5 19.2 1.5 29.6-1.2-30-6.1-52.5-32.5-52.5-64.4v-.8c8.7 4.9 18.9 7.9 29.6 8.3a65.447 65.447 0 0 1-29.2-54.6c0-12.2 3.2-23.4 8.9-33.1 32.3 39.8 80.8 65.8 135.2 68.6-9.3-44.5 24-80.6 64-80.6 18.9 0 35.9 7.9 47.9 20.7 14.8-2.8 29-8.3 41.6-15.8-4.9 15.2-15.2 28-28.8 36.1 13.2-1.4 26-5.1 37.8-10.2-8.9 13.1-20.1 24.7-32.9 34z"/>
</svg>
</a>
<a className="transition-colors hover:text-sky-500" target="_blank" rel="noreferrer"
href="https://www.linkedin.com/in/paulknulst">
<svg stroke="currentColor" fill="currentColor" strokeWidth="0" viewBox="0 0 448 512"
className="text-2xl" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
<path
d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"/>
</svg>
</a>
<a className="transition-colors hover:text-sky-500" target="_blank" rel="noreferrer"
href="https://github.com/paulknulst">
<svg stroke="currentColor" fill="currentColor" strokeWidth="0" viewBox="0 0 496 512"
className="text-2xl" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
<path
d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/>
</svg>
</a><a className="transition-colors hover:text-sky-500" target="_blank" rel="noreferrer"
href="https://paulknulst.medium.com">
<svg stroke="currentColor" fill="currentColor" strokeWidth="0" viewBox="0 0 448 512"
className="text-2xl" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
<path
d="M0 32v448h448V32H0zm372.2 106.1l-24 23c-2.1 1.6-3.1 4.2-2.7 6.7v169.3c-.4 2.6.6 5.2 2.7 6.7l23.5 23v5.1h-118V367l24.3-23.6c2.4-2.4 2.4-3.1 2.4-6.7V199.8l-67.6 171.6h-9.1L125 199.8v115c-.7 4.8 1 9.7 4.4 13.2l31.6 38.3v5.1H71.2v-5.1l31.6-38.3c3.4-3.5 4.9-8.4 4.1-13.2v-133c.4-3.7-1-7.3-3.8-9.8L75 138.1V133h87.3l67.4 148L289 133.1h83.2v5z"/>
</svg>
</a>
</div>
</div>
</div>
</div>
</div>
)
} export default Main;
The code will create a simple layout for a portfolio page with some introductory text about yourself on the left side. On the right side, it will have your profile picture with the links. Apart from this, it also contains some dummy text for the demo. Now you need to add the main component into the “index.tsx” file to see this page on your website preview. Remove all the content from the file first and then add the following code in it:
import type { NextPage } from 'next'
import Main from "@components/Main";
const Home: NextPage = () => {
return (
<div className="space-y-14 lg:space-y-24">
<main className="max-w-4xl mx-auto antialiased">
<Main/>
</main>
</div>
)
}
export default Home
By now you will have a simple homepage for your portfolio. You can create additional pages to meet your specific requirements. Based on your specific requirements and preferences, you can choose any deployment method for your portfolio app.
Create a Recipe Finder App using Next.js
- You need to create a Next.js code with Tailwind CSS by using the command
npx create-next-app -e with-tailwindcss recipe-app, this will install the packages and wait for a while as it might take time to install it.
- Once the code is generated, the folder name “recipe-app” will be created.
- Now open your “index.js” file, delete all the existing code and add the following code:
export default function Home() {
return (
<div className="flex flex-col md:px-12 px-0 relative bg-background font-raleway items-center min-h-screen">
<h1 className="text-6xl font-bold text-active mt-20">
Recipe Search
</h1>
<h2 className="text-primary text-2xl font-light mt-5">
Search recipes from all over the world.
</h2>
</div>
);
} - After that, open “app.js” file and add the following code:
import Head from 'next/head';
import 'tailwindcss/tailwind.css';
function MyApp({Component, pageProps}) {
return (
<>
<Head>
<title>RapidAPI - Recipe App</title>
<link rel="icon" href="/favicon.ico" />
<link
href="https://fonts.googleapis.com/css2?family=Raleway:wght@300;400;600;700;800&display=swap"
rel="stylesheet"
/>
</Head>
<Component {...pageProps} />
</>
);
}
export default MyApp;
Code to Create Homepage
export default function Home() {
return (
<div className="flex flex-col md:px-12 px-0 relative bg-background font-raleway items-center min-h-screen">
<h1 className="text-6xl font-bold text-active mt-20">Recipe Search</h1>
<h2 className="text-primary text-2xl font-light mt-5">
Search recipes from all over the world.
</h2>
<form
className="sm:mx-auto mt-20 md:max-w-4xl justify-center flex flex-col sm:w-full sm:flex"
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
}}
>
<input
type="text"
className="flex w-full rounded-lg px-5 py-3 text-base text-background font-semibold focus:outline-none focus:ring-2 focus:ring-active"
placeholder="Enter a recipe"
/>
<div className="mt-5 flex sm:flex-row flex-col justify-start">
<div className="sm:w-1/3 w-full">
<label className="block text-primary text-sm">Diet</label>
<select
className="mt-1 flex w-full rounded-lg px-5 py-3 text-base text-background font-bold focus:outline-none"
>
{[
"none",
"pescetarian",
"lacto vegetarian",
"ovo vegetarian",
"vegan",
"vegetarian",
].map((diet) => {
return <option value={diet}>{diet}</option>;
})}
</select>
</div>
<div className="sm:ml-10 sm:w-1/3 w-full">
<label className="block text-primary text-sm">
Exclude Ingredients
</label>
<input
type="text"
className="mt-1 w-full rounded-lg px-5 py-3 text-base text-background font-bold focus:outline-none"
placeholder="coconut"
></input>
</div>
</div>
<button
className="mt-5 w-full rounded-lg px-5 py-3 bg-active text-base text-primary font-bold hover:text-active hover:bg-primary transition-colors duration-300 sm:px-10"
type="submit"
>
Search
</button>
</form>
</div>
This code defines the structure for recipe search and includes a search form, title, and various input fields to customize search criteria. Tailwind CSS ensures a clean and responsive user interface.
Code to Store User Input
import { useState } from "react";
export default function Home() {
const [keyword, setKeyword] = useState(null); // Stores the input recipe name
const [diet, setDiet] = useState(null); // Stores the diet type`
const [exclude, setExclude] = useState(null); // Stores the excluded ingredients
const [response, setResponse] = useState(null); // Stores the response from the API
return (
<div className="flex flex-col md:px-12 px-0 relative bg-background font-raleway items-center min-h-screen">
<h1 className="text-6xl font-bold text-active mt-20">Recipe Search</h1>
<h2 className="text-primary text-2xl font-light mt-5">
Search recipes from all over the world.
</h2>
<form
className="sm:mx-auto mt-20 md:max-w-4xl justify-center flex flex-col sm:w-full sm:flex"
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
}}
>
<input
type="text"
className="flex w-full rounded-lg px-5 py-3 text-base text-background font-semibold focus:outline-none focus:ring-2 focus:ring-active"
placeholder="Enter a recipe"
onChange={(e) => {
setKeyword(e.target.value);
setResponse(null); // Removes previous response when user types a new recipe
}}
/>
<div className="mt-5 flex sm:flex-row flex-col justify-start">
<div className="sm:w-1/3 w-full">
<label className="block text-primary text-sm">Diet</label>
<select
className="mt-1 flex w-full rounded-lg px-5 py-3 text-base text-background font-bold focus:outline-none"
onChange={(e) => setDiet(e.target.value)}
>
{[
"none",
"pescetarian",
"lacto vegetarian",
"ovo vegetarian",
"vegan",
"vegetarian",
].map((diet) => {
return <option value={diet}>{diet}</option>;
})}
</select>
</div>
<div className="sm:ml-10 sm:w-1/3 w-full">
<label className="block text-primary text-sm">
Exclude Ingredients
</label>
<input
type="text"
className="mt-1 w-full rounded-lg px-5 py-3 text-base text-background font-bold focus:outline-none"
placeholder="cocunut"
onChange={(e) => setExclude(e.target.value)}
></input>
</div>
</div>
<button
className="mt-5 w-full rounded-lg px-5 py-3 bg-active text-base text-primary font-bold hover:text-active hover:bg-primary transition-colors duration-300 sm:px-10"
type="submit"
>
Search
</button>
</form>
</div>
Steps to Integrate the API
- You need to create a “.env_local” file in the root directory and add the following command:
NEXT_PUBLIC_RAPIDAPI_KEY=YOUR-RAPIDAPI-KEY
- Now, you need to subscribe to get the key from this link and replace the value of x-rapidapi-key.
- Then download and install “axios” by running the following command: npm install axios
- Once done, you need to import it into the index.js file
import axios from ‘axios’;
- Go to this link to generate a snippet in the preferred language and options.
- Next, you need to set up the API in the api directory create a “search.js” file, and add the following code.
// In pages/api/search.js:
import axios from 'axios';
export default async function handler(req, res) {
const options = {
method: 'GET',
url: 'https://spoonacular-recipe-food-nutrition-v1.p.rapidapi.com/recipes/search',
params: {
query: req.query.keyword,
diet: req.query.diet,
excludeIngredients: req.query.exclude,
number: '20',
offset: '0'
},
headers: {
'x-rapidapi-host':
'spoonacular-recipe-food-nutrition-v1.p.rapidapi.com',
'x-rapidapi-key': NEXT_PUBLIC_RAPIDAPI_KEY
}
};
try {
let response = await axios(options);
res.status(200).json(response.data);
} catch (error) {
console.error(error.response);
}
}
This code sets up the API route to handle requests for recipe search. It uses the Axios library to pass the necessary parameters and headers for search queries. Moreover, it ensures proper error handling if the API encounters any issue.
Code to Create Function to Get Recipe
import {useState} from 'react';
import axios from 'axios';
export default function Home() {
const [keyword, setKeyword] = useState(null);
const [diet, setDiet] = useState(null);
const [exclude, setExclude] = useState(null);
const [response, setResponse] = useState(null);
// Gets the recipes matching the input term
const getRecipes = async () => {
try {
diet === 'none' ? (diet = '') : null; // Remove diet if 'none' is selected
setLoading(true);
const res = await axios.get('api/search/', {
params: {keyword, diet, exclude} // Sending parameters to our API
});
const {data} = res; // Object destructuring to extract data from our response
setResponse(data.results); // Store results in the response state
} catch (error) {
console.error(error);
}
};
return (
<div className="flex flex-col md:px-12 px-0 relative bg-background font-raleway items-center min-h-screen">
<h1 className="text-6xl font-bold text-active mt-20">
Recipe Search
</h1>
<h2 className="text-primary text-2xl font-light mt-5">
Search recipes from all over the world.
</h2>
<form
className="sm:mx-auto mt-20 md:max-w-4xl justify-center flex flex-col sm:w-full sm:flex"
onSubmit={e => {
getRecipes(); // Trigger getRecipes function when search button is clicked
e.preventDefault();
e.stopPropagation();
}}
>
<input
type="text"
className="flex w-full rounded-lg px-5 py-3 text-base text-background font-semibold focus:outline-none focus:ring-2 focus:ring-active"
placeholder="Enter a recipe"
onChange={e => {
setKeyword(e.target.value);
setResponse(null);
}}
/>
<div className="mt-5 flex sm:flex-row flex-col justify-start">
<div className="sm:w-1/3 w-full">
<label className="block text-primary text-sm">
Diet
</label>
<select
className="mt-1 flex w-full rounded-lg px-5 py-3 text-base text-background font-bold focus:outline-none"
onChange={e => setDiet(e.target.value)}
>
{[
'none',
'pescetarian',
'lacto vegetarian',
'ovo vegetarian',
'vegan',
'vegetarian'
].map(diet => {
return <option value={diet}>{diet}</option>;
})}
</select>
</div>
<div className="sm:ml-10 sm:w-1/3 w-full">
<label className="block text-primary text-sm">
Exclude Ingredients
</label>
<input
type="text"
className="mt-1 w-full rounded-lg px-5 py-3 text-base text-background font-bold focus:outline-none"
placeholder="cocunut"
onChange={e => setExclude(e.target.value)}
></input>
</div>
</div>
<button
className="mt-5 w-full rounded-lg px-5 py-3 bg-active text-base text-primary font-bold hover:text-active hover:bg-primary transition-colors duration-300 sm:px-10"
type="submit"
>
Search
</button>
</form>
</div>
);
}
Code to Display the Recipe
{
"results": [
{
"id": 492560,
"title": "Quick and Easy St. Louis-Style Pizza",
"readyInMinutes": 27,
"servings": 8,
"sourceUrl": "https://www.cinnamonspiceandeverythingnice.com/st-louis-style-pizza/",
"openLicense": 0,
"image": "St--Louis-Style-Pizza-492560.jpg"
},
{
"id": 587203,
"title": "Taco Pizza",
"readyInMinutes": 20,
"servings": 6,
"sourceUrl": "https://laurenslatest.com/taco-salad-pizza-with-doritos/",
"openLicense": 0,
"image": "Taco-Salad-Pizza-with-Doritos-587203.jpg"
},
{
"id": 481601,
"title": "Neapolitan Pizza and Honey Whole Wheat Dough",
"readyInMinutes": 102,
"servings": 8,
"sourceUrl": "https://lifemadesimplebakes.com/2014/02/neapolitan-pizza-and-honey-whole-wheat-dough/",
"openLicense": 0,
"image": "Neapolitan-Pizza-and-Honey-Whole-Wheat-Dough-481601.jpg"
}
],
"baseUri": "https://spoonacular.com/recipeImages/",
"offset": 0,
"number": 3,
"totalResults": 257
}
This code will get the response from the API to retrieve recipe details such as names of the recipe, serving sizes, preparation time, and source URL along with the images.
Code to Display the Result with Grid Layout
import {useState} from 'react';
import axios from 'axios';
export default function Home() {
const [keyword, setKeyword] = useState(null);
const [diet, setDiet] = useState(null);
const [exclude, setExclude] = useState(null);
const [response, setResponse] = useState(null);
const getRecipes = async () => {
try {
diet === 'none' ? (diet = '') : null;
setLoading(true);
const res = await axios.get('api/search/', {
params: {keyword, diet, exclude}
});
const {data} = res;
setResponse(data.results);
} catch (error) {
console.error(error);
}
};
return (
<div className="flex flex-col md:px-12 px-0 relative bg-background font-raleway items-center min-h-screen">
<h1 className="text-6xl font-bold text-active mt-20">
Recipe Search
</h1>
<h2 className="text-primary text-2xl font-light mt-5">
Search recipes from all over the world.
</h2>
<form
className="sm:mx-auto mt-20 md:max-w-4xl justify-center flex flex-col sm:w-full sm:flex"
onSubmit={e => {
getRecipes();
e.preventDefault();
e.stopPropagation();
}}
>
<input
type="text"
className="flex w-full rounded-lg px-5 py-3 text-base text-background font-semibold focus:outline-none focus:ring-2 focus:ring-active"
placeholder="Enter a recipe"
onChange={e => {
setKeyword(e.target.value);
setResponse(null);
}}
/>
<div className="mt-5 flex sm:flex-row flex-col justify-start">
<div className="sm:w-1/3 w-full">
<label className="block text-primary text-sm">
Diet
</label>
<select
className="mt-1 flex w-full rounded-lg px-5 py-3 text-base text-background font-bold focus:outline-none"
onChange={e => setDiet(e.target.value)}
>
{[
'none',
'pescetarian',
'lacto vegetarian',
'ovo vegetarian',
'vegan',
'vegetarian'
].map(diet => {
return <option value={diet}>{diet}</option>;
})}
</select>
</div>
<div className="sm:ml-10 sm:w-1/3 w-full">
<label className="block text-primary text-sm">
Exclude Ingredients
</label>
<input
type="text"
className="mt-1 w-full rounded-lg px-5 py-3 text-base text-background font-bold focus:outline-none"
placeholder="cocunut"
onChange={e => setExclude(e.target.value)}
></input>
</div>
</div>
<button
className="mt-5 w-full rounded-lg px-5 py-3 bg-active text-base text-primary font-bold hover:text-active hover:bg-primary transition-colors duration-300 sm:px-10"
type="submit"
>
Search
</button>
</form>
{response && ( // Render only if response is not null
<div className="mt-10">
<div className="mt-6 grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
{response.map(recipe => (
<div key={recipe.id} className="pt-6">
<div className="flow-root bg-light rounded-lg px-4 pb-8">
<div className="-mt-6">
<div className="flex items-center justify-center">
<span className="p-2">
<img
src={
`https://spoonacular.com/recipeImages/` +
recipe.image
}
className="w-full h-full rounded-lg"
alt={recipe.id}
/>
</span>
</div>
<div className="text-center justify-center items-center">
<h3 className="mt-4 text-lg font-bold w-full break-words overflow-x-auto text-primary tracking-tight">
{recipe.title}
</h3>
<span className="mt-2 text-sm text-secondary block">
Ready in {recipe.readyInMinutes}{' '}
minutes - {recipe.servings}{' '}
Servings
</span>
<a
className="mt-4 text-sm text-active block"
href={recipe.sourceUrl}
>
Go to Recipe
</a>
</div>
</div>
</div>
</div>
))}
</div>
</div>
)}
</div>
);
}
Create a Weather App using Next.js
- First, create a new folder “weather-app” and open up the command prompt to create the Next.js app, using the following command.
npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion
- Once you’re done, install Axios by adding this command:
npm install axios
//or
yarn add axios
- After that, run the Next.js app using this command “npm run dev”.
- Now, open the Next.js app and open “globals.css” from the style folder then add this code “background-color: orange;”, this will change the background color of your app to orange.
Note: Do not use this to style your pages, add the above code into the body of “golbals.css” and only add the necessary CSS style.
Steps to Create the User Interface
- To build UI for your weather app, we are using the Chakra UI, add the following code to import the component in to your “_app.tsx” file.
import { ChakraProvider } from ‘@chakra-ui/react’
- After that, add the following code to wrap the “component” element. <ChakraProvider> <Component {…pageProps} /> </ChakraProvider>;
- Now, you need to create “Search.tsx” and “Card.tsx” folder inside the component folder.
- Next, import the search component inside the “inside.tsx” file and add the following code in the inside.tsx file.
import { Box } from "@chakra-ui/react";
import Head from "next/head";
import styles from "../styles/Home.module.css";
import Search from "../components/search";
export default function Home() {
const myStyle = {
backgroundColor: "orange",
minHeight: "100vh",
};
return (
<div className={styles.container} style={myStyle}>
<Head>
<title>Weather App</title>
<meta
name="An app showing weather details"
content="Generated by create next app"
/>
<link rel="icon" href="/favicon.ico" />
</Head>
<Box>
<Search />
</Box>
</div>
);
}
Steps to Create Search Box
- Open your terminal and add the following command to install the Charka UI icon package.
npm i @chakra-ui/icons
//or
yarn add @chakra-ui/icons
- Once installed, add the following code to import any icon.
- import <IconName> ‘@chakra-ui/react‘
- After that, add the following code to import the card component to perform conditional rendering.
import { Input } from '@chakra-ui/react'
import { Container } from '@chakra-ui/react'
import { IconButton } from '@chakra-ui/react'
import { SearchIcon } from '@chakra-ui/icons'
import { Flex } from '@chakra-ui/react'
import {useState, useEffect} from 'react'
import axios from 'axios'
import Card from './Card' And then add the following code to return a function to display the search box in your UI.
<>
<Container padding="10px" width="100vw">
<Flex>
<Input
placeholder="Enter Your City"
onChange={(e) => {
setSearchValue(e.target.value);
}}
/>
<IconButton
colorScheme="blue"
aria-label="Search database"
icon={<SearchIcon />}
onClick={handleClick}
/>
</Flex>
</Container>
</>;
Here, to create the search bar, we have used Charka UI components and style properties to import the container, icon button, search button, and input. The container creates a space to style other components and elements using props. The icon button and search button are obtained from the Charka UI icon library. Input takes input, which is similar to HTML.
Steps to Create Cards using Box Component
- Add the following code to get started:
import {
Flex,
Text,
Image,
Box,
SimpleGrid,
ListItem,
UnorderedList,
} from “@chakra-ui/react”; - Now, create an “image” folder in the public directory and copy all the background images in it. But make sure the names of the background images are short and add the following code.
bgImage=’url(./image/<imageName.jpg)’
// and
bgPosition=’bottom’ //center, top - Next, add the following code to style the box image:
<SimpleGrid columns={2} minChildWidth=”500px” placeItems=”center” spacing={16}>
<Box
m=”10px”
h=”500px”
w=”400px”
mt=”40px”
bgImage=”url(./img/cloudy.jpg)”
bgPosition=”bottom”
borderRadius=”2xl”
shadow=”dark-lg”
>
<Text
color=”white”
display=”flex”
justifyContent=”center”
mt=”5px”
fontSize=”20px”
>
Weather
</Text>
<Text color=”white” display=”flex” justifyContent=”center” mt=”200px”>
Current Weather
</Text>
</Box><Box
m=”10px”
h=”500px”
w=”400px”
mt=”40px”
bgImage=”url(./img/sunshine.jpg)”
bgPosition=”center”
borderRadius=”2xl”
shadow=”dark-lg”
>
<Flex wrap=”wrap” gap=”2″ justifyContent=”space-around”>
<Box>My city weather</Box>
<Box>City condition</Box>
</Flex>
</Box>
</SimpleGrid>;
- Now, import the card component as a card adding this code
import Card from “../components/Card”;
- Once done, replace the search component with the card within the code that will display two cards on your screen.
- In your index file, replace the card component with the search component.
Steps to fetch Request in Weather App
- Go to the search component above the return and add the following code to create three states.
const [searchValue, setSearchValue] = useState('');
const [weather, setWeather] = useState([]);
const [isData, setData] = useState(false);
Note: You can keep any name of your choice for these state variables.
- Now, you need to create a “handleClick” function below the states to handle the request from the search input.
- Next, add the following code for the “handleClick”:
const handleClick = () => {
const err = axios
.get(
`http://api.openweathermap.org/data/2.5/weather?q=${searchValue}&appid=f7dd5f65195d863069e051cef5e0e2ec&units=imperial`
)
.then((res) => {
setWeather(res.data);
console.log(res.data);
setData(true);
})
.catch((err) => {
err;
setData(false);
});
};
Here, we have used Axios to catch error if any, and gets the data. The weather state stores the weather data and then set the value to true (if it has a value) or false (if the weather state has no data), which ultimately, helps to determine the conditional rendering of the cards.
- After that, you need to make changes into your search component, so add the following code:
<>
<Container padding="10px" width="100vw">
<Flex>
<Input
placeholder="Enter Your City"
onChange={(e) => {
setSearchValue(e.target.value);
}}
/>
<IconButton
colorScheme="blue"
aria-label="Search database"
icon={<SearchIcon />}
onClick={handleClick}
/>
</Flex>
</Container>
//Conditional rendering
{isData ? <Card value={weather} /> : <div> oops no value </div>}
</>;
The above code renders the data if the data is true otherwise it renders the “div” element. And the value is stored in the card component is the data from API, which is stored in the weather state. That is being passed as “prop” to the card component for further use.
Step to Fetch Data from Front-End
- You need to add the following code to pass the data as a prop inside the card component.
const card = (props: any) => {
return()
}
export default cards; - After that, add this following code to handle data manipulation into your code:
const data = props.value; //stores props values in data
Here, we have pass value by referring to the key name in line 1 to line 6. Whereas, we have passed the icon number to lines 6 to 7 to retrieve the numbers and fetch the appropriate weather images icon. Similarly, line 9 to 36 fetches the month, day, hours, minutes, and date values. However, line 40 contains Unicode symbol for degrees.
const weatherItems = data.weather; //gets the values of weather
const cityName = data.name;
const cityMain = data.main;
const weatherForecast = data.main.feels_like;
const weatherIcon = Object.values(weatherItems)
.map((itm: any) => itm.icon)
.join("");
const url = `https://openweathermap.org/img/wn/${weatherIcon}@2x.png`;
//date and time
const dT = data.dt;
const time = data.timezone;
const cityMonth = new Date(dT * 1000 + time * 1000).getMonth();
const cityTime = new Date(dT * 1000 + time * 1000).getDay();
const minutes = new Date(dT * 1000 + time * 1000).getMinutes();
const hours = new Date(dT * 1000 + time * 1000).getHours();
const cityDate = new Date(dT * 1000 + time * 1000).getDate();
const cityMinutes = minutes < 10 ? `0` + minutes : minutes;
const cityHours = hours < 10 ? `0` + hours : hours;
const timeFormat = cityHours >= 12 ? "PM" : "AM";
const mainTime = `${cityHours}:${cityMinutes} ${timeFormat}`;
let val;
const dayArray = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
const day = dayArray[cityTime];
const monthArray = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
const month = monthArray[cityMonth];
let tempName: any = [];
let tempValue: any = [];
let dateSuffix;
switch (cityDate) {
case 2:
dateSuffix = "nd";
break;
case 3:
dateSuffix = "rd";
break;
default:
dateSuffix = "th";
}
const fullDate = `${month} ${day} ${cityDate + dateSuffix}`;
const unicode = "\u00b0";
- Next, add the following code to return the data for humidity, temperature, and pressure along with the city name and date.
let weatherArray = [fullDate, cityName, mainTime];
//weather key names
Object.keys(cityMain)
.filter((val, index) => index != 1)
.map((key) => {
tempName.push(key);
});
//weather value numbers
Object.values(cityMain)
.filter((val, index) => index != 1)
.map((val) => {
tempValue.push(val);
});
//main weather key name and value to display
let mainTemp = tempName.map((val: any, index: any) => {
return `${val} : ${tempValue[index]}`;
});
<SimpleGrid columns={2} minChildWidth="500px" placeItems="center" spacing={16}>
<Box
m="10px"
h="500px"
w="400px"
mt="40px"
bgImage="url(./img/cloudy.jpg)"
bgPosition="bottom"
borderRadius="2xl"
shadow="dark-lg"
>
{weatherArray.map((element, index) => (
<UnorderedList>
<ListItem
color="white"
display="flex"
justifyContent="center"
mt="20px"
key={index}
>
{element}
</ListItem>
</UnorderedList>
))}
<Image
src={url}
alt="weather-icon"
width={100}
height={100}
ml="155"
p="0"
/>
<Text
color="white"
display="flex"
justifyContent="center"
mt="5px"
fontSize="20px"
>
{weatherForecast}
{unicode}
</Text>
<Text color="white" display="flex" justifyContent="center" mt="200px">
{" "}
Current Weather{" "}
</Text>
</Box>
<Box
m="10px"
h="500px"
w="400px"
mt="40px"
bgImage="url(./img/sunshine.jpg)"
bgPosition="center"
borderRadius="2xl"
shadow="dark-lg"
>
<Flex wrap="wrap" gap="2" justifyContent="space-around">
{mainTemp.map((val: any, index: any) => (
<Box
color="white"
display="flex"
justifyContent="center"
alignItems="center"
p="5"
w="150px"
key={index}
>
{" "}
{val}{" "}
</Box>
))}
</Flex>
</Box>
</SimpleGrid>;
- After that, open your “next.config.js” file and add the following code in the “module exports”, and then you’re all set and ready with your weather app:
{
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'openweathermap.org',
},
],
},
}
In conclusion
Exploring these projects will give you a hands-on experience and when you master it, go ahead and build more real-world applications. It will provide you with new opportunities and a rewarding journey. Next.js is one such tool that comes packed with robust features. Moreover, it has a large community, and documentation support provides great help whenever you’re stuck on something. As you gain more confidence using Next.js then solving the complex web development process will be a cakewalk for you.
Take control of your career and land your dream job!
Sign up and start applying to the best opportunities!
FAQs
It is crucial for beginners to understand the basic concepts of Next.js first. Once you grasp the basic concept, you should learn how to use API, data fetching, components, and composition, etc.
Learning Next.js is simple and quite easy as compared to other React frameworks. On top of that, it has built-in support for server-side rendering, a large community, and well-maintained documentation that provides seamless web development.
You should handle a couple of simpler projects when you start to gain confidence and expertise. Later, you can start practicing on complex projects.
The career prospects are quite lucrative for Next.js developers as more and more companies using Next.js framework to build SEO-friendly websites. One can be a full-stack developer, front-end developer, Next.js specialist, freelance developer, and E-commerce developer.