38
votes

Very similar to this angular question: how do I use anchor links for in-page navigation when using react-router?

In other words, how do I implement the following plain HTML when using react-router?

<a href="#faq-1">Question 1</a>
<a href="#faq-2">Question 2</a>
<a href="#faq-3">Question 3</a>

<h3 id="faq-1">Question 1</h3>
<h3 id="faq-2">Question 2</h3>
<h3 id="fa1-3">Question 3</h3>

Currently I intercept clicks on such links, and scroll to the anchor position. This isn't satisfactory, because it means it's impossible to link directly to some section of a page.

4
Someone edited this question into a totally different quesiton. This is about anchor links. - starwed
I would love to know the answer to this as well. They've said they "don't support this," which seems ridiculous when the product is a router. - Mike
@Mike - I'd be interested to hear your comment on my answer as I believe that should resolve the issue if you try it? - Colin Ramsay
Your answer may be in this thread: https://github.com/rackt/react-router/issues/770 - Mike
I ran into the same problem and solved it by intercepting the onClick of the anchor and using a scrollTo solution in place of the default browser behavior of the anchor tags. I agree with @Mike that this is rather ridiculous. - Katie Kilian

4 Answers

18
votes

The problem with anchor links is that react-router's default is to use the hash in the URL to maintain state. Fortunately, you can swap out the default behaviour for something else, as per the Location documentation. In your case you'd probably want to try out "clean URLs" using the HistoryLocation object, which means react-router won't use the URL hash. Try it out like this:

Router.run(routes, Router.HistoryLocation, function (Handler) {
  React.render(<Handler/>, document.body);
});
12
votes

React Router Hash Link worked for me. Easy to install and implement:

$ npm install --save react-router-hash-link

In your component.js import it as Link:

import { HashLink as Link } from 'react-router-hash-link';

And instead of using an anchor <a>, use <Link> :

<Link to="#faq-1>Question 1</Link>
<Link to="#faq-2>Question 2</Link>
<Link to="#faq-3>Question 3</Link>

NOTE: I used HashRouter instead of Router

4
votes

import { Link } from 'react-router-dom'

Link using

<Link to='/homepage#faq-1'>Question 1</Link>

Then insert the following code inside your target React component (Homepage):

useEffect(() => {
    const hash = props.history.location.hash
    // Check if there is a hash and if an element with that id exists
    const el = hash && document.getElementById(hash.substr(1))
    if (el) {    
        el.scrollIntoView({behavior: "smooth"})
    }
}, [props.history.location.hash]) // Fires every time hash changes
2
votes

Using current methods you would use Link from react-router-dom

<a href="#faq-1">Question 1</a>

would be accomplished with

import React from 'react';
import {Link} from 'react-router-dom';

and using

<Link to={{pathname: '/this-view-path', hash: '#faq-1'}}>Question 1</Link>

of course '/this-view-path' could be provided as a variable from your project