Constructing a Tennis Trivia App With Subsequent.js and Netlify

No Comments

Immediately we will likely be studying tips on how to construct a tennis trivia app utilizing Subsequent.js and Netlify. This know-how stack has change into my go-to on many tasks. It permits for speedy growth and simple deployment.

With out additional ado let’s soar in!

What we’re utilizing

Subsequent.jsNetlifyTypeScriptTailwind CSS

Why Subsequent.js and Netlify

You might assume that this can be a easy app which may not require a React framework. The reality is that Subsequent.js provides me a ton of options out of the field that permit me to only begin coding the principle a part of my app. Issues like webpack configuration, getServerSideProps, and Netlify’s automated creation of serverless capabilities are just a few examples.

Netlify additionally makes deploying a Subsequent.js git repo tremendous simple. Extra on the deployment a bit afterward.

What we’re constructing

Mainly, we’re going to construct a trivia recreation that randomly reveals you the identify of a tennis participant and you need to guess what nation they’re from. It consists of 5 rounds and retains a working rating of what number of you get right.

The information we want for this software is an inventory of gamers together with their nation. Initially, I used to be considering of querying some stay API, however on second thought, determined to only use an area JSON file. I took a snapshot from RapidAPI and have included it within the starter repo.

The ultimate product appears to be like one thing like this:

Yow will discover the ultimate deployed model on Netlify.

Starter repo tour

If you wish to observe alongside you’ll be able to clone this repository after which go to the beginning department:

git clone git@github.com:brenelz/tennis-trivia.git
cd tennis-trivia
git checkout begin

On this starter repo, I went forward and wrote some boilerplate to get issues going. I created a Subsequent.js app utilizing the command npx create-next-app tennis-trivia. I then proceeded to manually change a pair JavaScript information to .ts and .tsx. Surprisingly, Subsequent.js robotically picked up that I wished to make use of TypeScript. It was too simple! I additionally went forward and configured Tailwind CSS utilizing this text as a information.

Sufficient speak, let’s code!

Preliminary setup

Step one is establishing setting variables. For native growth, we do that with a .env.native file. You possibly can copy the .env.pattern from the starter repo.

cp .env.pattern .env.native

Discover it at present has one worth, which is the trail of our software. We are going to use this on the entrance finish of our app, so we should prefix it with NEXT_PUBLIC_.

Lastly, let’s use the next instructions to put in the dependencies and begin the dev server: 

npm set up
npm run dev

Now we entry our software at http://localhost:3000. We should always see a reasonably empty web page with only a headline:

Creating the UI markup

In pages/index.tsx, let’s add the next markup to the prevailing Residence() operate:

export default operate Residence() {
return (
<div className=”bg-blue-500″>
<div className=”max-w-2xl mx-auto text-center py-16 px-4 sm:py-20 sm:px-6 lg:px-8″>
<h2 className=”text-3xl font-extrabold text-white sm:text-4xl”>
<span className=”block”>Tennis Trivia – Subsequent.js Netlify</span>
</h2>
<div>
<p className=”mt-4 text-lg leading-6 text-blue-200″>
What nation is the next tennis participant from?
</p>
<h2 className=”text-lg font-extrabold text-white my-5″>
Roger Federer
</h2>

<type>
<enter
checklist=”nations”
kind=”textual content”
className=”p-2 outline-none”
placeholder=”Select Nation”
/>
<datalist id=”nations”>
<choice>Switzerland</choice>
</datalist>
<p>
<button
className=”mt-8 w-full inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-blue-600 bg-white hover:bg-blue-50 sm:w-auto”
kind=”submit”
>
Guess
</button>
</p>
</type>

<p className=”mt-4 text-lg leading-6 text-white”>
<sturdy>Present rating:</sturdy> 0
</p>
</div>
</div>
</div>
);

This varieties the scaffold for our UI. As you’ll be able to see, we’re utilizing a number of utility lessons from Tailwind CSS to make issues look a bit prettier. We even have a easy autocomplete enter and a submit button. That is the place you’ll choose the nation you assume the participant is from after which hit the button. Lastly, on the backside, there’s a rating that modifications primarily based on right or incorrect solutions.

Establishing our knowledge

For those who check out the information folder, there needs to be a tennisPlayers.json with all the information we are going to want for this software. Create a lib folder on the root and, within it, create a gamers.ts file. Keep in mind, the .ts extension is required since is a TypeScript file. Let’s outline a kind that matches our JSON knowledge..

export kind Participant = {
id: quantity,
first_name: string,
last_name: string,
full_name: string,
nation: string,
rating: quantity,
motion: string,
ranking_points: quantity,
};

That is how we create a kind in TypeScript. We’ve the identify of the property on the left, and the kind it’s on the best. They are often primary sorts, and even different sorts themselves.

From right here, let’s create particular variables that symbolize our knowledge:

export const playerData: Participant[] = require(“../knowledge/tennisPlayers.json”);
export const top100Players = playerData.slice(0, 100);

const allCountries = playerData.map((participant) => participant.nation).kind();
export const uniqueCountries = […Array.from(new Set(allCountries))];

A pair issues to notice is that we’re saying our playerData is an array of Participant sorts. That is denoted by the colon adopted by the kind. In actual fact, if we hover over the playerData we are able to see its kind:

In that final line we’re getting a singular checklist of nations to make use of in our nation dropdown. We go our nations right into a JavaScript Set, which eliminates the duplicate values. We then create an array from it, and unfold it into a brand new array. It could appear pointless however this was finished to make TypeScript completely happy.

Imagine it or not, that’s actually all the information we want for our software!

Let’s make our UI dynamic!

All our values are hardcoded at present, however let’s change that. The dynamic items are the tennis participant’s identify, the checklist of nations, and the rating.

Again in pages/index.tsx, let’s modify our getServerSideProps operate to create an inventory of 5 random gamers in addition to pull in our uniqueCountries variable.

import { Participant, uniqueCountries, top100Players } from “../lib/gamers”;

export async operate getServerSideProps() {
const randomizedPlayers = top100Players.kind((a, b) => 0.5 – Math.random());
const gamers = randomizedPlayers.slice(0, 5);

return {
props: {
gamers,
nations: uniqueCountries,
},
};
}

No matter is within the props object we return will likely be handed to our React element. Let’s use them on our web page:

kind HomeProps = {
gamers: Participant[];
nations: string[];
};

export default operate Residence({ gamers, nations }: HomeProps) {
const participant = gamers[0];

}

As you’ll be able to see, we outline one other kind for our web page element. Then we add the HomeProps kind to the Residence() operate. We’ve once more specified that gamers is an array of the Participant kind.

Now we are able to use these props additional down in our UI. Exchange “Roger Federer” with {participant.full_name} (he’s my favourite tennis participant by the best way). You need to be getting good autocompletion on the participant variable because it lists all of the property names we’ve got entry to due to the kinds that we outlined.

Additional down from this, let’s now replace the checklist of nations to this:

<datalist id=”nations”>
{nations.map((nation, i) => (
<choice key={i}>{nation}</choice>
))}
</datalist>

Now that we’ve got two of the three dynamic items in place, we have to sort out the rating. Particularly, we have to create a bit of state for the present rating.

export default operate Residence({ gamers, nations }: HomeProps) {
const [score, setScore] = useState(0);

}

As soon as that is finished, substitute the 0 with {rating} in our UI.

Now you can verify our progress by going to http://localhost:3000. You possibly can see that each time the web page refreshes, we get a brand new identify; and when typing within the enter area, it lists the entire out there distinctive nations.

Including some interactivity

We’ve come an honest method however we have to add some interactivity.

Hooking up the guess button

For this we have to have a way of realizing what nation was picked. We do that by including some extra state and attaching it to our enter area.

export default operate Residence({ gamers, nations }: HomeProps) {
const [score, setScore] = useState(0);
const [pickedCountry, setPickedCountry] = useState(“”);

return (

<enter
checklist=”nations”
kind=”textual content”
worth={pickedCountry}
onChange={(e) => setPickedCountry(e.goal.worth)}
className=”p-2 outline-none”
placeholder=”Select Nation”
/>

);
}

Subsequent, let’s add a guessCountry operate and fix it to the shape submission:

const guessCountry = () => {
if (participant.nation.toLowerCase() === pickedCountry.toLowerCase()) {
setScore(rating + 1);
} else {
alert(‘incorrect’);
}
};

<type
onSubmit={(e) => {
e.preventDefault();
guessCountry();
}}
>

All we do is mainly examine the present participant’s nation to the guessed nation. Now, after we return to the app and guess the nation proper, the rating will increase as anticipated.

Including a standing indicator

To make this a bit nicer, we are able to render some UI relying whether or not the guess is right or not.

So, let’s create one other piece of state for standing, and replace the guess nation methodology:

const [status, setStatus] = useState(null);

const guessCountry = () => {
if (participant.nation.toLowerCase() === pickedCountry.toLowerCase()) {
setStatus({ standing: “right”, nation: participant.nation });
setScore(rating + 1);
} else {
setStatus({ standing: “incorrect”, nation: participant.nation });
}
};

Then render this UI beneath the participant identify:

{standing && (
<div className=”mt-4 text-lg leading-6 text-white”>
<p>
You might be {standing.standing}. It’s {standing.nation}
</p>
<p>
<button
autoFocus
className=”outline-none mt-8 w-full inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-blue-600 bg-white hover:bg-blue-50 sm:w-auto”
>
Subsequent Participant
</button>
</p>
</div>
)}

Lastly, we wish to be certain our enter area doesn’t present after we are in an accurate or incorrect standing. We obtain this by wrapping the shape with the next:

{!standing && (
<type>

</type>
)}

Now, if we return to the app and guess the participant’s nation, we get a pleasant message with the results of the guess.

Progressing by means of gamers

Now in all probability comes essentially the most difficult half: How can we go from one participant to the subsequent?

Very first thing we have to do is retailer the currentStep in state in order that we are able to replace it with a quantity from 0 to 4. Then, when it hits 5, we wish to present a accomplished state for the reason that trivia recreation is over.

As soon as once more, let’s add the next state variables:

const [currentStep, setCurrentStep] = useState(0);
const [playersData, setPlayersData] = useState(gamers);

…then substitute our earlier participant variable with:

const participant = playersData[currentStep];

Subsequent, we create a nextStep operate and hook it as much as the UI:

const nextStep = () => {
setPickedCountry(“”);
setCurrentStep(currentStep + 1);
setStatus(null);
};

<button
autoFocus
onClick={nextStep}
className=”outline-none mt-8 w-full inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-blue-600 bg-white hover:bg-blue-50 sm:w-auto”
>
Subsequent Participant
</button>

Now, after we make a guess and hit the subsequent step button, we’re taken to a brand new tennis participant. Guess once more and we see the subsequent, and so forth. 

What occurs after we hit subsequent on the final participant? Proper now, we get an error. Let’s repair that by including a conditional that represents that the sport has been accomplished. This occurs when the participant variable is undefined.

{participant ? (
<div>
<p className=”mt-4 text-lg leading-6 text-blue-200″>
What nation is the next tennis participant from?
</p>

<p className=”mt-4 text-lg leading-6 text-white”>
<sturdy>Present rating:</sturdy> {rating}
</p>
</div>
) : (
<div>
<button
autoFocus
className=”outline-none mt-8 w-full inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-indigo-600 bg-white hover:bg-indigo-50 sm:w-auto”
>
Play Once more
</button>
</div>
)}

Now we see a pleasant accomplished state on the finish of the sport.

Play once more button

We’re nearly finished! For our “Play Once more” button we wish to reset the state the entire recreation. We additionally wish to get a brand new checklist of gamers from the server without having a refresh. We do it like this:

const playAgain = async () => {
setPickedCountry(“”);
setPlayersData([]);
const response = await fetch(
course of.env.NEXT_PUBLIC_API_URL + “/api/newGame”
);
const knowledge = await response.json();
setPlayersData(knowledge.gamers);
setCurrentStep(0);
setScore(0);
};

<button
autoFocus
onClick={playAgain}
className=”outline-none mt-8 w-full inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-indigo-600 bg-white hover:bg-indigo-50 sm:w-auto”
>
Play Once more
</button>

Discover we’re utilizing the setting variable we arrange earlier than by way of the method.env object. We’re additionally updating our playersData by overriding our server state with our consumer state that we simply retrieved.

We haven’t crammed out our newGame route but, however that is simple with Subsequent.js and Netlify serverless capabilities . We solely have to edit the file in pages/api/newGame.ts.

import { NextApiRequest, NextApiResponse } from “subsequent”
import { top100Players } from “../../lib/gamers”;

export default (req: NextApiRequest, res: NextApiResponse) => {
const randomizedPlayers = top100Players.kind((a, b) => 0.5 – Math.random());
const top5Players = randomizedPlayers.slice(0, 5);
res.standing(200).json({gamers: top5Players});
}

This appears to be like a lot the identical as our getServerSideProps as a result of we are able to reuse our good helper variables.

If we return to the app, discover the “Play Once more” button works as anticipated.

Enhancing focus states

One very last thing we are able to do to enhance our person expertise is about the give attention to the nation enter area each time the step modifications. That’s only a good contact and handy for the person. We do that utilizing a ref and a useEffect:

const inputRef = useRef(null);

useEffect(() => {
inputRef?.present?.focus();
}, [currentStep]);

<enter
checklist=”nations”
kind=”textual content”
worth={pickedCountry}
onChange={(e) => setPickedCountry(e.goal.worth)}
ref={inputRef}
className=”p-2 outline-none”
placeholder=”Select Nation”
/>

Now we are able to navigate a lot simpler simply utilizing the Enter key and typing a rustic.

Deploying to Netlify

You might be questioning how we deploy this factor. Effectively, utilizing Netlify makes it as simple as it detects a Subsequent.js software out of the field and robotically configures it.

All I did was arrange a GitHub repo and join my GitHub account to my Netlify account. From there, I merely choose a repo to deploy and use all of the defaults.

The one factor to notice is that you need to add the NEXT_PUBLIC_API_URL setting variable and redeploy for it to take impact.

Yow will discover my remaining deployed model right here.

Additionally notice which you can simply hit the “Deploy to Netlify” button on the GitHub repo.

Conclusion

Woohoo, you made it! That was a journey and I hope you discovered one thing about React, Subsequent.js, and Netlify alongside the best way.

I’ve plans to broaden this tennis trivia app to make use of Supabase within the close to future so keep tuned!

You probably have any questions/feedback be happy to succeed in out to me on Twitter.

The publish Constructing a Tennis Trivia App With Subsequent.js and Netlify appeared first on CSS-Tips. You possibly can assist CSS-Tips by being an MVP Supporter.

    About Marketing Solution Australia

    We are a digital marketing company with a focus on helping our customers achieve great results across several key areas.

    Request a free quote

    We offer professional SEO services that help websites increase their organic search score drastically in order to compete for the highest rankings even when it comes to highly competitive keywords.

    Subscribe to our newsletter!

    More from our blog

    See all posts

    Leave a Comment