Search code examples
reactjsgatsbyblogsreach-routermdxjs

Using Gatsby Link to navigate to MDX rendered pages


I am looking to Link to blog posts.

import React from "react";
import styled from "@emotion/styled";
import { css } from "@emotion/react";
import { Link, Button } from "gatsby";
import Image from "gatsby-image";
import { navigate } from "@reach/router";

const BlogArticle = styled.article`
  border-bottom: 1px solid #ddd;
  display: flex;
  margin-top: 0;
  padding-bottom: 1rem;

  :first-of-type {
    margin-top: 1rem;
  }
`;

const ImageLink = styled("div")`
  margin: 1rem 1rem 0 0;
  width: 100px;
`;

const ReadNavigate = styled(Link)`
  display: inline-block;
  font-size: 0.8rem;
  font-family: "Oswald";
`;

const TutorialPreview = ({ post }) => {
  console.log(post.slug);
  return (
    <BlogArticle>
      <ImageLink onClick={() => navigate(post.slug)}>
        <Image
          fluid={post.image.sharp.fluid}
          css={css`
            * {
              margin-top: 0;
            }
          `}
          alt={post.title}
        />
      </ImageLink>
      <div
        css={css`
          padding-top: 1rem;
        `}
      >
        <h3 onClick={() => navigate(post.slug)}>{post.title}</h3>
        <p>{post.excerpt}</p>
        <ReadNavigate to="/tire-machine-basics">
          &rarr; Read this post
        </ReadNavigate>
      </div>
    </BlogArticle>
  );
};

export default TutorialPreview;

The above is my template for a preview on the home page which works fine for my preview, in the case of the page that lists all the posts through the behavior of the Link component assumes the slug should be attached to the current page stack.

e.g.

on home Link = /{post.slug}

on blog list Link = tutorials/{post.slug}

The issue is that the post pages are generated using the slug at the pages level not nested in tutorials. I tried to circumvent using the navigate() method from reach router but that has the issue of these pages not existing until you use the Link component to navigate to them initially.

I was wondering if there were any ideas on how to circumvent this without hard coding the path so that I don't need a separate component.


Solution

  • Link component assumes the slug should be attached to the current page stack

    That's not true.

    Paths are relative to what you are telling to the <Link> component. For example, being at /posts page:

    <Link to="/about-me">
    

    Will take you to localhost:8000/about-me. Being now at /about-me, a link like:

     <Link to="/posts/article-1">
    

    Will take you to localhost:8000/posts/article-1. However, being at /posts/article-1 a link like:

     <Link to="about-me">
    

    Will take you to localhost:8000/posts/article-1/about-me due to the relativity.

    You need to add an initial slash (/) to make it relative to your slug, simply as that. Exactly the same behavior as the standards anchors (<a>). Applied to your code:

    <Link to={`/${post.slug}`}>
    

    In addition, you've made a weird wrapping with ImageLink component, wrap your content inside a component if needed but don't change the div's behavior to navigate. It's better to use:

    <Link to={`/${post.slug}`}>
       <Image>
    </Link>