32

I am currently creating share buttons with Gatsby and would like to share content based on the current url, which changes depending on the environment and the current page. With GoHugo this can be called with {{ .Permalink }}. Does anyone know how to do this with Gatsby?

I have a ShareButtons component, which is a child of BlogPostTemplate.

David
  • 4,191
  • 2
  • 31
  • 40
  • I believe it's quite different in an environment like Gatsby. The first question I would like to ask is, in which place exactly do use need this information? Cause it really depends and also in a componentized application you may need to take this information from somewhere and pass it down to other components. – kbariotis Jun 21 '18 at 22:23
  • Thanks for your comment. I have a ShareButtons component, which is a child of BlogPostTemplate. – David Jun 22 '18 at 05:41
  • I did it like this: https://github.com/kbariotis/kostasbariotis.com/blob/master/src/templates/blog-post.js#L134. Basically, I am constructing the URL in order to pass it to the share component. Usually, on the pages/templates components you already know the URL of the current page so you don't need a variable for it. From there, you just pass it down to other components. – kbariotis Jun 22 '18 at 08:40

4 Answers4

39

You can get the current url using the location prop from the @reach/router Location component.

import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { Location } from '@reach/router';

class SomeComponent extends Component {
  static propTypes = {
    location: PropTypes.object.isRequired
  }

  render() {
    const { location } = this.props;
    return <div>{JSON.stringify(location)}</div>;
  }
}

export default props => (
  <Location>
    {locationProps => <SomeComponent {...locationProps} {...props} />}
  </Location>
);
Félix Paradis
  • 5,165
  • 6
  • 40
  • 49
Clay Risser
  • 3,272
  • 1
  • 25
  • 28
24

Gatsby uses react-router behind the scene meaning location information is available in props. This information can be used in a conditional statement or passed into styled-components like so:

<Component isIndex={this.props.location.pathname === '/'}>

fstep
  • 673
  • 1
  • 8
  • 13
  • 10
    This doesn't work anymore since Gatsby v2 replaced `react-router` with `@reach/router`. How is it done now? – Robin Métral Dec 09 '18 at 10:21
  • 2
    For Gatsby v2 it is beautifully explained in the docs: https://www.gatsbyjs.com/docs/migrating-from-v1-to-v2/#4-pass-history-location-and-match-props-to-layout – Raman Sinclair Oct 29 '20 at 13:43
19

You can use useLocation like p.boiko suggested like so:

import * as React from 'react';
import { useLocation } from '@reach/router';

const UserTheme = () => {
  const location = useLocation();
  console.log(location)  
};

Output would be:

{pathname: "/", search: "", hash: "", href: "http://localhost:8000/", origin: "http://localhost:8000", …}
DᴀʀᴛʜVᴀᴅᴇʀ
  • 7,681
  • 17
  • 73
  • 127
Thien Phan
  • 358
  • 4
  • 8
3

If like me, you just wanted to know how to get a uri 'for a component' and this whole issue confused you because of the general complexity of the solutions and documentation out there compared to that simple need, another way that does not involve understanding reach router (which is a nice thing to understand but a bit heavy for simply getting the uri at build time) is to pass your location as a prop from a page. This works well if you want to use the uri for things like setting defaultActiveKey on bootstrap menus where the menu itself it not the only way to access that page and so "activeClassName" does not always work. It also works at build time. Whatever, it gives you access to the uri in a component.

I don't think this will work for headless CMS type implementations but there are other ways of dealing with that.

If you haven't used props much before then these are things you can pass around your pages and components (simplification) and I would recommend you look up how to use them. By default in Gatsby, pages have a location pathname property so you can tell your component about that location from the calling page by passing it as a prop. In English, this would be 'Use this component with its location set to the property "location.pathname" of me, the calling page". The component now has the location.

What you need to do is create a page like so

import React from "react"
import NavComponent from "../../components/navComponent"

const APage = (props) => {
  return (
     <NavComponent location={props.location.pathname}/>
  )
}
export default APage

For the hard of thinking (like me), the location={props.location.pathname} bit means that in the component, your props will now have a location value and it will be set to the location.pathname of the page that called it. Therefore, in your Nav component you now have access to the uri. Remember that to get it, your component needs to receive props before it can use them. The result is something like so (pointless to do this but it gives the idea).

import React from "react"

const NavComponent = (props) => {
  return (

        <Nav data-uri={props.location}>
        </Nav>  

  )
}

export default NavComponent

When you are on APage then data-uri will be whatever that is for APage and on BPage, whatever it will be for that.

matthias_h
  • 11,356
  • 9
  • 22
  • 40