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 an expert?

    Here's how it works πŸ‘‡

    Leave your email and I'll send you thoughtfully written emails every week about React, JavaScript, and your career. Lessons learned over 20 years in the industry working with companies ranging from tiny startups to Fortune5 behemoths.

    Join Swizec's Newsletter

    And get thoughtful letters πŸ’Œ on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.

    "Man, love your simple writing! Yours is the only newsletter I open 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 15,161+ engineers just like you already growing their careers with my emails, workshops, books, and courses.

    ⭐️⭐️⭐️⭐️✨
    4.5 stars average rating

    Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.

    Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.

    Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help πŸ‘‰ swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.

    Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers πŸ‘‰ ServerlessHandbook.dev

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

    Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections

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

    Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog

    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 by Swizec with ❀️