30
loading...
This website collects cookies to deliver better user experience
npx create-next-app@latest custom-error-component
npm run dev
inside that newly created directory and inspecting the Next.js default page on localhost:3000
import Link from 'next/link';
export default function Home() {
return (
<div className="home-container">
<h2>Welcome to my amazing Rick and Morty Page!</h2>
<div className="img-container">
<img src="https://rickandmortyapi.com/api/character/avatar/2.jpeg"></img>
<img src="https://rickandmortyapi.com/api/character/avatar/1.jpeg"></img>
</div>
<div className="link-container">
<Link href="/characters">
<a>
Show me Rick and Morty Characters!
</a>
</Link>
<Link href="/locations">
<a>
Show me Rick and Morty locations!
</a>
</Link>
</div>
</div>
)
}
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}
a {
color: inherit;
text-decoration: none;
}
* {
box-sizing: border-box;
}
/* styles for index.js */
.home-container {
min-height: 100vh;
display: flex;
flex-direction: column;
gap: 2rem;
justify-content: center;
}
.home-container h2 {
text-align: center;
}
.img-container {
display: flex;
gap: 2rem;
justify-content: center;
}
a {
border: 1px solid black;
padding: 0.6rem 1rem;
border-radius: 5px;
}
.link-container {
display: flex;
justify-content: center;
gap: 2rem;
}
/* styles for locations.js */
.locations-container {
max-width: 1100px;
margin: auto;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
margin-block: 2rem;
}
.locations-container a {
align-self: baseline;
justify-self: baseline;
}
.locations-container a:nth-of-type(2) {
justify-self: end;
}
.locations-container h2 {
text-align: center;
}
article {
border: 1px solid black;
border-radius: 5px;
padding: 0 1rem;
}
/* styles for characters.js */
.character-card {
padding: 1rem;
display: grid;
grid-template-columns: auto 1fr;
gap: 1rem;
}
/* styles for the error page */
.error-container {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
import React, { useEffect, useState } from 'react';
import Link from 'next/link'
function Locations(rops) {
const [locations, setLocations] = useState({});
useEffect( () => {
fetch("https://rickandmortyapi.com/api/location")
.then(res => res.json())
.then(data => setLocations(data));
}, [])
return (
<div className="locations-container">
<Link href="/"><a>Back to home</a></Link>
<h2>Rick and Morty Locations</h2>
<Link href="/characters"><a>Show me Rick and Morty Characters!</a></Link>
{
locations.results?.map((location) => (
<article key={location.id}>
<p>Name: {location.name}</p>
<p>Dimension: {location.dimension}</p>
<p>Type: {location.type}</p>
</article>))
}
</div>
);
}
export default Locations;
import React from 'react';
import Link from 'next/link'
function Characters(props) {
return (
<div className="locations-container">
<Link href="/"><a>Back to home</a></Link>
<h2>Rick and Morty Characters</h2>
<Link href="/locations"><a>Show me Rick and Morty Locations!</a></Link>
{
props.characters.results.map( (character) => (
<article key={character.id} className="character-card">
<img src={character.image} alt={character.name} height="200px" />
<div>
<p>{character.name}</p>
<p>{character.location.name}</p>
</div>
</article>
))
}
</div>
);
}
export default Characters;
export async function getServerSideProps(context) {
const characters = await fetch("https://rickandmortyapi.com/api/character").then(res => res.json());
return { props: { characters}}
}
location
in the API call for something else, like for example locaon
character
with charter
or something else that does not exist.npm run build
to create a production buildnpm run start
to start that production build locally._error.js
in the pages folder. You can find the documentation about this page in the Next.js docs: Customized Error Component. Copy and paste the code from the docs and adapt it to go with the look and feel of your application. Mine looks like this:import Link from 'next/link';
function Error({ statusCode }) {
return (
<div className="error-container">
<img src="https://rickandmortyapi.com/api/character/avatar/234.jpeg" alt="a dead morty..."/>
{statusCode && <h1>Error: {statusCode}</h1>}
<p>We are sorry! There was an error</p>
<Link href="/">
<a>Go back home</a>
</Link>
</div>
)
}
Error.getInitialProps = ({ res, err }) => {
const statusCode = res ? res.statusCode : err ? err.statusCode : 404
return { statusCode }
}
locations.js
first. Leave the typo we introduced earlier and call https://rickandmortyapi.com/api/locaon
instead of location, we will get back an object looking like this: { error: 'There is nothing here'}
.const [locations, setLocations] = useState({});
useEffect( () => {
fetch("https://rickandmortyapi.com/api/locaon")
.then(res => res.json())
.then(data => setLocations(data));
}, [])
if(locations.error) {
return <Error />
}
return (
<div className="locations-container">
<Link href="/"><a>Back to home</a></Link>
npm run build
npm run start
. Now you can visit your production build on localhost:3000
localhost:3000/characters
, you will see our error component, with additional information we didn't see in our client-side rendered component: