Swizec Teller - a geek with a hatswizec.com

    Variants – a quick tip for better React components

    Say you're building a component that shows up in lots of places, like a header.

    Look at designs and sure enough, same header on every page. Logo, few buttons, username. You create a reusable component. DRY all the way.

    const Header = () => {
    return (
    <Box>
    <Logo />
    <MenuItem />
    <MenuItem />
    <UserMessages />
    <UserProfile />
    </Box>
    )
    }

    Fantastic! You have a header that works everywhere.

    A new page appears

    "Hey, header looks weird on homepage. Where's the signup button?"

    Your designer's not happy. Header that's the same everywhere can't be same on the homepage. That's for marketing, they need signups.

    obviously πŸ™„

    You add a prop.

    const Header = (props: { showSignup: boolean }) => {
    return (
    <Box>
    <Logo />
    <MenuItem />
    <MenuItem />
    {!props.showSignup && <UserMessages />}
    {!props.showSignup && <UserProfile />}
    {props.showSignup && <SignupButton />}
    </Box>
    )
    }

    Cool, you've kept it DRY. Same header, same styling, signup yes or no.

    A funnel shows up

    "Hey, users are getting distracted out of this purchase funnel. Header too busy"

    Your universal header is costing you money. When users are on the path to paying, you want nothing to stand in their way.

    Another boolean!

    "Oh and let's pretend this is a fullscreen modal, add a close button. Keep the logo"

    Two booleans!

    aqV7k1png2f49bb

    const Header = (props: {
    showSignup: boolean
    hideMenu: boolean
    showClose: boolean
    }) => {
    return (
    <Box>
    <Logo />
    {!props.hideMenu && <MenuItem />}
    {!props.hideMenu && <MenuItem />}
    {!props.showSignup && <UserMessages />}
    {!props.showSignup && <UserProfile />}
    {props.showSignup && <SignupButton />}
    {props.showClose && <CloseButton />}
    </Box>
    )
    }

    Well that's not confusing at all. With 3 booleans, your header has 8 possible incantations.

    Possible incantations of Header component
    Possible incantations of Header component

    Add one more ask from design and you're up to 16.

    πŸ˜…

    You've created a mess

    Your beautiful universal header component is hard to use. Complexity is exploding, the code is getting hairy, and you're the only person on your team who knows how to hold it.

    For everyone else it's frustrating as heck. Get it right for this screen, breaks on that screen.

    Debugging feels like whack-a-mole.

    And I'm showing you a simple example. In production code these booleans start interacting. If hideMenu and showSignup then do X, otherwise if not showClose do Y.

    Nobody wants to touch your component ever again. It's too tricky.

    Variants to the rescue

    How many of those 8 incantations are valid?

    I count 3.

    Identify your variants
    Identify your variants

    Then why allow the other 5? If 5 out of 8 ways to use your component are bugs, something's wrong.

    Here's what you do πŸ‘‰ turn those flags into a variant prop. Use TypeScript and you even get autocomplete 😍

    const Header = (props: { variant: "homepage" | "funnel" }) => {
    let hideMenu, showClose, showSignup
    switch (variant) {
    case "homepage":
    showSignup = true
    case "funnel":
    hideMenu = true
    showClose = true
    }
    return (
    <Box>
    <Logo />
    {!hideMenu && <MenuItem />}
    {!hideMenu && <MenuItem />}
    {!showSignup && <UserMessages />}
    {!showSignup && <UserProfile />}
    {showSignup && <SignupButton />}
    {showClose && <CloseButton />}
    </Box>
    )
    }

    Now the rest of your team can use your header with ease: <Header variant="..." />. And thanks to TypeScript their IDE tells them what's available.

    AND we found a bug in my pseudocode. You don't want user menus showing up in funnel headers πŸ˜…

    Cheers,
    ~Swizec

    PS: quick tip for shorter emails πŸ‘‰ break your wrist

    Swizec Teller published ServerlessHandbook.dev avatarSwizec Teller published ServerlessHandbook.dev@Swizec
    And then I broke my wrist a little πŸ˜…
    Tweet media

    Did you enjoy this article?

    Published on March 2nd, 2021 in Technical, React, Lessons

    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 over 14,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 ❀️