Categories
Gatsby.js

Gatsby.js — Scroll Position, Dynamic Navigation, and Link States

Spread the love

Gatsby is a static web site framework that’s based on React.

We can use it to create static websites from external data sources and more.

In this article, we’ll look at how to create a site with Gatsby.

Scroll Restoration

We can restore the scrolling position after refresh with Gatsby.

For example, we can write:

import React from "react"
import { useScrollRestoration } from "gatsby"

const IndexPage = () => {
  const ulScrollRestoration = useScrollRestoration(`page-component-ul-list`)

return (
    <ul style={{ height: 200, overflow: `auto` }} {...ulScrollRestoration}>
      {Array(100).fill().map((_, i) => i).map(n => (
        <li key={n}>{n}</li>
      ))}
    </ul>
  )
}

export default IndexPage

We use the useScrollRestoration hook with the 'page-component-ul-list' argument to let us create an object to restore the scrolling position.

Then we spread that object’s properties as props of the ul to let us restore the scrolling position.

Location Data from Props

We can get location data from props.

To do this, we write:

gatsby-config.js

module.exports = {
  siteMetadata: {
    siteURL: 'http://example.com'
  }
}

src/pages/foo.js

import React from "react"
import { graphql } from "gatsby"

const FooPage = ({ location, data }) => {
  const canonicalUrl = data.site.siteMetadata.siteURL + location.pathname
  return <div>The URL of this page is {canonicalUrl}</div>
}

export const query = graphql`
  query PageQuery {
    site {
      siteMetadata {
        siteURL
      }
    }
  }
`

export default FooPage

We get the siteMetadata.siteURL from the gatsby-config.js via the GraphQL query.

Then we get the location prop’s pathname property to get the path to the FooPage .

So we should see:

The URL of this page is http://example.com/foo

displayed when we go to http://localhost:8000/foo.

Providing State to a Link Component

We can provide state to a Link component.

For example, we write:

src/pages/index.js

import { Link } from "gatsby"
import React from "react"

const IndexPage = () => {
  return <>
    <div>hello world</div>
    <Link
      to={'/foo'}
      state={{ id: 1 }}
    >
      go to foo
    </Link>
  </>
}

export default IndexPage

src/pages/foo.js

import React from "react"

const FooPage = ({ location }) => {
  const { state = {} } = location
  const { id } = state
  return <div>id: {id}</div>
}

export default FooPage

We pass an object into the state prop.

Then in FooPage , we get the location prop’s state.id property to get the id property that we passed into the state prop.

Dynamic Navigation

We can add navigation dynamically with Gatsby.

To do this, we write:

module.exports = {
  siteMetadata: {
    title: 'Gatsby Starter',
    menuLinks: [
      {
        name: 'home',
        link: '/'
      },
      {
        name: 'foo',
        link: '/foo'
      }
    ]
  },
  plugins: []
}

src/components/layout.js

import React from "react"
const { StaticQuery, Link } = require("gatsby");

const Header = ({ siteTitle, menuLinks }) => (
  <header
    style={{
      background: "green",
      marginBottom: "1.45rem",
    }}
  >
    <div>
      <h1 style={{ margin: 5, flex: 1 }}>
        <Link
          to="/"
          style={{
            color: "white",
            textDecoration: "none",
          }}
        >
          {siteTitle}
        </Link>
      </h1>
      <div>
        <nav>
          <ul style={{ display: "flex", flex: 1 }}>
            {menuLinks.map(link => (
              <li
                key={link.name}
                style={{
                  listStyleType: `none`,
                  padding: `1rem`,
                }}
              >
                <Link style={{ color: `white` }} to={link.link}>
                  {link.name}
                </Link>
              </li>
            ))}
          </ul>
        </nav>
      </div>
    </div>
  </header>
)

const Layout = ({ children }) => (
  <StaticQuery
    query={graphql`
        query SiteTitleQuery {
          site {
            siteMetadata {
              title
              menuLinks {
                name
                link
              }
            }
          }
        }
      `}
    render={data => (
      <>
        <Header menuLinks={data.site.siteMetadata.menuLinks} siteTitle={data.site.siteMetadata.title} />
        <div
          style={{
            margin: '0 auto',
            maxWidth: 960,
            padding: '0px 1.0875rem 1.45rem',
            paddingTop: 0,
          }}
        >
          {children}
        </div>
      </>
    )}
  />
)

export default Layout;

src/pages/index.js

import { Link } from "gatsby"
import React from "react"
import Layout from "../components/layout"

const IndexPage = () => {
  return <>
    <Layout>
      <div>hello world</div>
    </Layout>
  </>
}

export default IndexPage

src/pages/foo.js

import React from "react"
import Layout from "../components/layout"

const FooPage = () => {
  return <div>
    <Layout>
      <div>foo</div>
    </Layout>
  </div>
}

export default FooPage

We add the menuLinks array into gatsby-config.js to add the data for the links.

Then in layout.js , we get the link data and then render them.

The Header component takes the siteTitle and menuLinks props and render the data into HTML.

siteTitle has the title of the site.

menuLinks is an array of data that we have from gatsby-config.js ‘s menuLinks property.

Then in the Layout component, we add the StaticQuery component to make the query for the menu link data.

The render prop has the result of the query in the data parameter.

And we render the links and title with the Header component.

The div has the child components that we have inside the Layout component tags.

Conclusion

We can restore the scroll position after refresh with Gatsby.

Also, we can get location data from props.

And we can create links dynamically from the site’s metadata.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *