Roy Prins
Roy Prins

Reputation: 3080

Avoid entering URLs manually in the React components

I am taking my first steps with Gatsby, and I find that I am repeating myself frequently. One example is making links, where in several places I do something like:

import {kebabCase} from "lodash";

// ...
    <Link to={`tags/${kebabCase(tag)}`}>
      {tag}
    </Link>

It feels wrong to create the to argument in several places, and when I decide to change the URL format (for example: tag/... instead of tags/...) I will have to change all occurrences.

I know that the Django framework solves this by using "named urls". You can identify the URL by keyword, and provide arguments. It will then return the properly formatted URL. Is something like this part of Gatsby or React, or any other way to solve this?

Naively, my code example would be:

import {urlmaker} from "urlutil"

//...
    <Link to={urlmaker(`tag`, { tagname: {tag} })}>
      {tag}
    </Link>

I think this is not too hard to implement myself, but I am curious for any standardized React or Gatsby way to handle this.

Upvotes: 1

Views: 2083

Answers (2)

Roy Prins
Roy Prins

Reputation: 3080

Posting this as an answer, but hopefully somebody more knowledgable will come up with a more standardized approach.

The functionality I require can be achieved by creating an object to take care of the routes.

utilities/routing.js

import {kebabCase} from "lodash";

export const makeRoute = {
  tagPage: ({tag}) => `/tag/${kebabCase(tag)}/`,
  blogPage: ({title, date}) => `/blog/${date}_${kebabCase(title)}/`
};

Now you have defined the routes in a central place, for use in your React components or other configuration files:

component.js

import {makeRoute} from "../utilities/routing";
...
        <Link to={ makeRoute.tagPage({tag}) }>
          {tag}
        </Link>

For consistency in Gatsby, also use this method to in the createPage api. Gatsby registers the pages in React-router and we want them to match up, obviously.

gatsby-node.js

import {makeRoute} from "utilities/routing";
...
    createPage({
      path: makeRoute.tagPage({tag}),
      component: path.resolve("./src/templates/tag.js"),
      context: { tag, },
    });

Upvotes: 1

Bhojendra Rauniyar
Bhojendra Rauniyar

Reputation: 85545

You can define a constant globally and utilize it so that you only need to change the value where you have defined the constant when you need it. For eg. you may define development and production environment constant:

// Development Environment
const TAGS = 'tags';

// Production Environment
const TAGS = 'pro-tags';

And then you can simply use that constant.

<Link to={`${TAGS}/${kebabCase(tag)}`}>

Now, when your app runs in production environment, it will be 'pro-tags' and so on.


Update: You can also make a component and utilize the props to route the link, following is just an example:

export class OptionalLink extends React.Component {

    render( ) {

     return this.props.dateProp
       ? <Link to={`${this.props.dateProp}/${this.props.pathProp}`} {... this.props} />
       : <Link to={`${someDefaultDate}/${this.props.pathProp}}`} { ... this.props} />;

    }
};

Now, you can use <OptionalLink dateProps="2018-apr-23" pathProp={kebabCase(tag)} />

I hope you can manage this way.

Upvotes: 3

Related Questions