reactjsurlgatsbyurl-routingdomain-name

How do I route all pages in this format /@{username} to a template page? - Gatsby.js


I just created a website using Gatsby.js, and want my users to be able to access their own profile pages by adding the "@" sign after my site URL, followed by their usernames (example.com/@username).

Is there any way I can tell gatsby to just route that user to a template file that I created called User.js where I will read the username from the URL, fetch data, and populate the page with that data?

Is this behavior even possible in Gatsby? I appreciate all your help!

I've asked Chatgpt but it keeps telling me to fetch a full list of users first in gatsby-node.js, and build all their pages during build time, which is definitely not ideal.

I have also considered Deferred Static Generation (DSG), where I would fetch all usernames from my database, create a deferred page for each user which only get rendered on the client side when users type in /@username url. However, this means that whenever a new user signs up, the site has to rebuild for them to have their own profile domain, which also doesn't work.


Solution

  • There are no doubt many ways to do this. My simple approach would be to use dynamic redirects.

    🗎 src/pages/[...].js

    import React from "react";
    import User from "./user";
    
    export default function DynamicRoute(props) {
        const slug = props.params[`*`];
    
        if (slug && slug.startsWith("@")) {
            return (
                <div>
                  <User handle={slug.slice(1)} />
                </div>
              ); 
        }
    }
    

    That checks whether the requested page begins with an @ and, if so, renders the User component. Now we just need to define a simple User component.

    🗎 src/pages/user.js

    import React from "react"
    import Layout from "../layouts"
    
    export default function User({ handle }) {
        console.log(handle);
        return (
            <Layout>
                <h1>User Page: {handle}</h1>
            </Layout>
        )
    }
    

    The component accepts a handle argument which is interpolated into the <h1> tag. You can (should and no doubt will!) do something more interesting than that. See this for a few more details.