5
votes

I'm using gatsby js and trying to figure out how to have a page level side bar with Gatsby links that render a new component inside a div in the same page I can do this using react-router-dom but in Gatsby all I can find is how to create blog posts which is driving me nuts as every tutorial I find is the same blog post.

enter image description here

Here is my layout page /layouts/index.js

export default ({ children }) => (
  <div id="layout">
    <header>
      <h3>Header</h3>
      <MainNav />
    </header>
    {children()}
  </div>
)

About Page /pages/about.js

export default ({ location, match }) => {
  console.log('location = ', location, 'match = ', match );
  return (
    <div id="about">
      <SideBar />
      <div id="content">
        // . add child template or component for link clicked in sidebar
      </div>
    </div>
  );
};

What I'm trying to do is when a user clicks on a link in the side bar stay on about but render a new component or template based on the gatsby-link clicked in the about sidebar.

The About SideBar component /components/about/side-bar.js

const SideBar = () => {
  return (
    <div id="side-bar">
      {/* <li><Link to='/about?sort=name'>work</Link></li> */}
      <li><Link to="/about/work">work</Link></li>
      <li><Link to='/about/hobbies'>hobbies</Link></li>
      <li><Link to='/about/buildings'>buildings</Link></li>
    </div>
  )
}

Problem with the links above, they are trying to go to a new page called. /about/work This is not what I'm trying to do. Again I'm trying to make it stay on about but render a new component inside the content div.

Please help gatsby is so all over the place as far as docs goes. ok maybe its just me and not getting the docs clearly. Thanks

UPDATE: I tried adding a page suing createPage which works for me kind of but it doesn't pass the match.params id

gatsby-node.js

exports.createPages = ({ boundActionCreators }) => {
  const { createPage } = boundActionCreators;
  const myComponent = path.resolve('src/pages/about/index.js');
  createPage({
    path: '/about/:id',
    component: myComponent
  })
}
1
Pass some props <SideBar location={location} match={match}/>and use them - search for 'conditional rendering' ? - xadm
Thanks xadm but the location will render a new page. I'm trying not to render a new page. Instead I want to render a template of a new component inside the <div id="content"> in the same about page. - me-me
router 'switches' components for different routes. When not using route than change a value in local state, pass it as prop to both (SideBar and Content) component. Inside them render conditionally what you need. - xadm
Sorry I don't understand what you are saying. Gatsby Link is using routes under the hood, that's the whole purposes of it. I want to use Route so user can click back and forth in browser. Using local state is not going to produce that route behavior. - me-me
It contains menu (uses Link from gatsby-link) passed as prop. EducationsPage (and others) is linked from main menu (like router). . For footer menu it uses own menu structure (its tricky created, just use common array of objects) passed to container (your layout with sidebar). Educations is a content (used in container as {props.children}). This {props.children} is like content placeholder in template. - xadm

1 Answers

7
votes

After a long time of trying to understand Gatsby and I can say I still don't as its docs are vast and not very clear. But once I started to look at the node-apis and onCreatePage it gave me some ideas. This is what the docs literally say.

onCreatePage

Called when a new page is created. This extension API is useful for programmatically manipulating pages created by other plugins e.g. if you want paths without trailing slashes.

So the only part in here that gives me a hint of this might be the key to helping me is this line. useful for programmatically manipulating pages created by other plugins

Anyway this got me writing some code at least. Then about 3 hours later I found a plugin that was doing exactly what I was trying to do with this method. The plugin is called gatsby-plugin-create-client-paths key here is client-paths!!!!!

This makes life worth living! So in my case above I just wanted to be able to use Gatsby's router ( which is just react-router-dom behind the scenes), to pass me and id or value to routers match.params object. It still doesn't but what it does do is checks for any path after a prefix like /folder/ in my case '/about/work and recreate the page with a template component (in my case keep using pages/about/index.js), which is my template. Now that we have about/index.js rendering for ever link after /about/ then we can use some internal switch statement to handle the location that is been passed to /about/index.js. Still don't get match.params update but I do get props.location.pathname; which allows me to extract everything after the prefix to use in a switch statement to render my specific components based on the routes pathname. Enough rabbiting on here is a rough solution to show as an example.

So add the plugin as an npm install. open up gatsby.config.js and add the below code to the exports.

module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-create-client-paths`,
      options: { prefixes: [`/about/*`] },
    },
  ]
} 

Then in my main about page pages/about/index

import React from "react";
import SideBar from '../../components/about/side-nav';

export default (props) => {
  const { pathname } = props.location;
  var n = pathname.lastIndexOf('/');
  var pageId = pathname.substring(n + 1);

  const page = () => {
    switch(pageId){
      case '': 
        return (
          <div>Work Page</div>
        );
      case 'work':
        return (
          <div>Work Page</div>
        );
      case 'hobbies':
        return (
          <div>Hobbies Page</div>
        );
      case 'buildings':
      return (
        <div>buildings Page</div>
      );
    }
  }
  return (
    <div id="about">
      <SideBar />
      <div id="content">
        {page()}
      </div>
    </div>
  );
};

Then in my sidebar I call it like this.

  <li><Link to="/about/work">work</Link></li>
  <li><Link to='/about/hobbies'>hobbies</Link></li>
  <li><Link to='/about/buildings'>buildings</Link></li>

Hopefully this will help someone else out. After all this I'm starting to really question the bulk of gatsby especially with docs not been very clear. Based on the response to my question I guess not many people in stackoverflow's community are using Gatsby which is worrying when you need help. It does look like Gatsby's github community is very helpful but that should be for bug issues and not for questions like mine, but encouraging to see.

Hope this helps someone.