Skip to content
Swizec Teller - a geek with a hatswizec.com

Your first NextJS app โ€“ CodeWithSwiz

CodeWithSwiz is a twice-a-week live series. Like a podcast with video and fun hacking. Focused on experiments. Join live Wednesdays and Sundays

In this episode we tried NextJS, a React webapp framework, and built a small app. You can see it live at swiz-cms.vercel.app.

The ultimate goal for this app is to help folks create markdown articles. Copypasta is fine, but I always forget to change the title, write a description, add categories, and create a social card.

In 55min we went from "Never tried NextJS before" to a working app with a design system, forms, static rendering, and talking to an AWS Lambda to make cards. Not bad.

The end result
The end result

Initial setup

npx create-next-app swiz-cms

That creates a plain ol' NextJS app. You get pleasant default styling, support for file-based routing, and server-side-rendering/generation out of the box.

Means you can add a new page by creating a file in pages/file.js. Anything in there becomes a page.

You get support for building APIs out of the box via pages/api, but we didn't try that on this stream. Next time ๐Ÿ˜‰

Wish you got MDX support out of the box. Makes for a better experience writing landing pages, product descriptions, and other content-heavy materials.

I'm sure there's a plugin for that ๐Ÿค”

Adding a design system

I like to use theme-ui as a base for my design systems. Comes with flexible theming support and a great set of default components.

yarn add theme-ui @theme-ui/presets

Installs theme-ui and default presets with configured themes.

In NextJS, you add a root <ThemeProvider> in the _app.js file. Lets you wrap the component tree and gives you access to theming anywhere in your app.

// pages/_app.js
import { ThemeProvider } from "theme-ui"
import theme from "../styles/theme"
function MyApp({ Component, pageProps }) {
return (
<ThemeProvider theme={theme}>
<Component {...pageProps} />
</ThemeProvider>
)
}

We created a custom theme in styles/theme.js that extends from the deep preset. Because deep's colors looked pretty :)

// styles/theme.js
import { deep } from "@theme-ui/presets"
export default {
...deep,
sizes: {
...deep.sizes,
container: 1024,
},
}

Custom container size means we can center our app with <Container> ... </Container>. Might need to add more sizes to make it responsive.

Yes, theme-ui has support for that ๐Ÿค˜

Creating a form

Forms are notoriously difficult and that's why we used my new favorite form library, react-hook-form. It's great.

// components/FrontmatterForm.js
import { useForm } from "react-hook-form"
import { Label, Input, Textarea, Button } from "theme-ui"
export const FrontmatterForm = ({ onSubmit }) => {
const { register, handleSubmit } = useForm()
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Label>Title</Label>
<Input name="title" ref={register} />
<Label>Description</Label>
<Textarea name="description" ref={register} />
<Button type="submit" bg="secondary">
Submit
</Button>
</form>
)
}

Our form is simple โ€“ย title and description โ€“ย and react-hook-form made it even simpler. ref={register} sets up state management machinery, theme-ui default components make it pretty.

When you hit submit, the onSubmit callback gets values in a dictionary.

We put them in a useState inside the main page.

// pages/index.js
export default function Home() {
const [frontmatter, setFrontmatter] = useState(null);
return (
<>
<Container>
<h1>Swiz CMS is where articles are born</h1>
<p>Use this to setup your copypasta for a new article</p>
<FrontmatterForm onSubmit={setFrontmatter} />
<Box sx={{ p: 4 }}>
{frontmatter ? <SocialCardImage {...frontmatter} /> : null}
{frontmatter ? <Frontmatter {...frontmatter} /> : null}
</Box>
</Container>

FrontmatterForm returns data when it's ready, sets state, and re-renders the page. That shows 2 new result components.

Talking to a serverless function on AWS Lambda

We used react-query for talking to a server. An AWS Lambda running my screenshot machinery in this case.

// components/SocialCardImage.js
import { useQuery } from "react-query"
import { Image, Spinner } from "theme-ui"
async function fetchSocialCard(key, title) {
const res = await fetch(
`https://pifc233qp6.execute-api.us-east-1.amazonaws.com/dev/social-card?title=${title}`
)
return res.json()
}
export const SocialCardImage = ({ title }) => {
const cardQuery = useQuery(["social-card", title], fetchSocialCard)
if (cardQuery.isLoading) {
return <Spinner />
}
return <Image src={cardQuery.data.url} />
}

React Query is like Apollo Client, but for REST. It's fantastic.

You give your query a name, define a fetch function that returns data, and library handles the rest. Deals with caching, deduping, refetching, and coordination between different components making the same request.

Proper article on React Query coming soon.

Verdict on NextJS

๐Ÿ‘

Cheers,
~Swizec

Did you enjoy this article?

Published on September 1st, 2020 in CodeWithSwiz, Livecoding, Technical

Learned something new?
Want to become a high value JavaScript expert?

Here's how it works ๐Ÿ‘‡

Leave your email and I'll send you an Interactive Modern JavaScript Cheatsheet ๐Ÿ“–right away. After that you'll get thoughtfully written emails every week about React, JavaScript, and your career. Lessons learned over my 20 years in the industry working with companies ranging from tiny startups to Fortune5 behemoths.

Start with an interactive cheatsheet ๐Ÿ“–

Then get thoughtful letters ๐Ÿ’Œ on mindsets, tactics, and technical skills for your career.

"Man, love your simple writing! Yours is the only email I open from marketers and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. ๐Ÿ‘Œ"

~ Ashish Kumar

Join over 10,000 engineers just like you already improving their careers with my letters, workshops, courses, and talks. โœŒ๏ธ

Have a burning question that you think I can answer?ย I don't have all of the answers, but I have some! Hit me up on twitter or book a 30min ama for in-depth help.

Ready to Stop copy pasting D3 examples and create data visualizations of your own? ย Learn how to build scalable dataviz components your whole team can understand with React for Data Visualization

Curious about Serverless and the modern backend? Check out Serverless Handbook, modern backend for the frontend engineer.

Ready to learn how it all fits together and build a modern webapp from scratch? Learn how to launch a webapp and make your first ๐Ÿ’ฐ on the side with ServerlessReact.Dev

Want to brush up on your modern JavaScript syntax?ย Check out my interactive cheatsheet: es6cheatsheet.com

By the way, just in case no one has told you it yet today: I love and appreciate you for who you areย โค๏ธ

Created bySwizecwith โค๏ธswizec.com