39

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.

Community
  • 1
  • 1
starwed
  • 2,536
  • 2
  • 25
  • 39
  • 3
    Someone edited this question into a totally different quesiton. This is about [anchor links](https://www.google.com/search?q=anchor+links). – starwed Mar 08 '15 at 18:08
  • 3
    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 Apr 09 '15 at 19:00
  • @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 Apr 10 '15 at 10:02
  • Your answer may be in this thread: [https://github.com/rackt/react-router/issues/770](https://github.com/rackt/react-router/issues/770) – Mike Apr 10 '15 at 12:35
  • 2
    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 Apr 10 '15 at 15:46
  • @CharlieKilian That's what I do currently, but it doesn't allow for proper linking... – starwed Apr 10 '15 at 23:06
  • @starwed I think what you're currently doing is the best approach with React, it's just not very typical to link like this - you probably want to take this to GH. https://github.com/rackt/react-router/issues/394 – Benjamin Gruenbaum Apr 10 '15 at 23:14

5 Answers5

19

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);
});
Colin Ramsay
  • 16,086
  • 9
  • 52
  • 57
14

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

maledr53
  • 1,359
  • 11
  • 7
7

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
Noa
  • 207
  • 4
  • 4
5

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

JoeFlash
  • 74
  • 1
  • 3
0

For Router 6 use can use the following:

const {hash, key} = useLocation()
useEffect(()=>{
    if(hash){
       const targetElement = document.getElementById(hash.substring(1))
        targetElement?.scrollIntoView({behavior: 'smooth'})
    }
}, [key, hash])