How to build a Gravatar Icon with Next.js
Preview: https://with-nextjs-and-gravatar.vercel.app/
Building the app
Initialize a Nextjs app
npx create-next-app@latest --use-npm my-gravatar-app
Next, install the Node.js library for Gravatar.
npm install gravatar
Setup an API Endpoint
Create a JavaScript file to handle the network request and send the data back to the client. /pages/api/gravatar.js
const gravatar = require("gravatar");
/**
* @param {Object} req - Express request object
* @param {Object} req.body - Express request body
* @param {string} req.body.email - User email
* @returns {string} - Gravatar URL
*/
export default function handler(req, res) {
if (req.method === "POST") {
const { email } = req.body;
try {
const avatar = gravatar.url(
email,
{ s: "100", r: "x", d: "retro" },
true
);
res.status(200).json({ avatar });
} catch (error) {
res.status(500).json({ error });
}
} else {
res.status(405).json({ error: "Method not allowed" });
}
}
Create the React Components
In a new file, create a React component called Gravatar. This component won’t do anything fancy, just render the avatar if a source is provided. ./components/Gravatar.jsx
export default function Gravatar({ email = "", avatar = "", size = 80 }) {
return (
<div>
{avatar && (
<img
className="gravatar"
src={avatar}
alt={email}
width={size}
height={size}
/>
)}
</div>
);
}
(Optional) Create a Loading component to account for loading behavior. You could add a better loading icon that what has been present here, we’re just foucsed on simplicity. ./components/Loading.jsx
export default function Loading() {
return <div>Loading...</div>;
}
Now modify the pages/index.js
to serve both of these components.
import { useEffect, useState } from "react";
import Gravatar from "../components/Gravatar";
import Loading from "../components/Loading";
export default function Home() {
const [email, setEmail] = useState("your@email.here");
const [avatar, setAvatar] = useState("");
const [loading, setLoading] = useState(true);
useEffect(() => {
updateAvatar();
}, []);
const updateAvatar = async () => {
setLoading(true);
setAvatar("");
const response = await fetch("/api/gravatar", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ email }),
});
const { avatar } = await response.json();
setLoading(false);
setAvatar(avatar);
};
return (
<div className="container">
<main>
{loading && <Loading />}
{avatar && <Gravatar email={email} avatar={avatar} size={100} />}
</main>
</div>
);
}
Launch the app
Back into the application’s terminal, run the development script listed in the package.json. Open the browser to localhost:3000 and you should see the completed app.
npm run dev
Bonus: Dynamically update the Gravatar Icon
So far we’ve covered how to set the Gravatar Icon on when the app loads. Let’s go a step further an make create a form that will accept a user’s email address as an input, and then update the Gravatar icon when the user submits the form. ./components/GravatarChanger.jsx
export default function GravatarChanger({
email = "",
disabled = false,
onChange,
onSubmit,
}) {
return (
<form onSubmit={onSubmit}>
<label>Gravatar Tester</label>
<span>Try your email address to see your Gravatar</span>
<input
type="email"
value={email}
onChange={onChange}
placeholder="Enter your email address"
/>
<button type="submit" disabled={disabled}>
Change Gravatar
</button>
</form>
);
}
Then, modify the home page to accommodate this new component.
import { useEffect, useState } from 'react';
import Gravatar from '../components/Gravatar';
import Loading from '../components/Loading';
import GravatarChanger from '../components/GravatarChanger';
export default function Home() {
const [email, setEmail] = useState('');
const [avatar, setAvatar] = useState('');
const [loading, setLoading] = useState(true);
useEffect(() => {
updateAvatar();
}, []);
const handleEmailChange = (event) => {
setEmail(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
updateAvatar();
};
const updateAvatar = async () => {
setLoading(true);
setAvatar('');
const response = await fetch('/api/gravatar', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email })
});
const { avatar } = await response.json();
setLoading(false);
setAvatar(avatar);
};
return (
<div className='container'>
<main>
{loading && <Loading />}
{avatar && <Gravatar email={email} avatar={avatar} size={100} />}
<GravatarChanger
disabled={loading}
email={email}
onChange={handleEmailChange}
onSubmit={handleSubmit}
/>
</main>
</div>
);
}
At this point you have a Gravatar component that can be changed based on user input!