Cat_Enthusiast
Cat_Enthusiast

Reputation: 15698

React-router-dom using "#" in Link path does not navigate to Component

I'm trying to create a feature where when a user clicks on a <Link>, they navigate to another component (Post) and scroll directly to a Comment. The path satisfies the requirements for the <Route> definition, but when I use a "#" as part of the URL, the redirect does not take affect:

Route: <Route path="/post/:id/:hash" component={Post} />

URL: https://b881s.codesandbox.io/post/4/#ve33e

However, what's interesting is that the feature works as expected when I use a "@" instead of "#".

URL: https://b881s.codesandbox.io/post/4/@ve33e

I've tried to find any mentions of "#" being some sort of special character to react-router-dom, but have not found anything. Maybe there's something I'm fundamentally missing here?

Here's the sandbox with working code: https://codesandbox.io/s/scrollintoview-with-refs-and-redux-b881s

App.js

import React from "react";
import ReactDOM from "react-dom";
import Home from "./Home";
import Posts from "./Posts";
import Post from "./Post";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import store from "./store";
import { Provider } from "react-redux";

import "./styles.css";

const App = () => {
  return (
    <Provider store={store}>
      <BrowserRouter>
        <div>
          <Switch>
            <Route path="/" exact component={Home} />
            <Route path="/posts" component={Posts} />
            <Route path="/post/:id/:hash" component={Post} />
            <Route path="/post/:id/" component={Post} />
          </Switch>
        </div>
      </BrowserRouter>
    </Provider>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Posts.js

import React from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";

class Posts extends React.Component {
  createPostList = () => {
    const { posts } = this.props;

    if (posts.posts) {
      return posts.posts.map(post => {
        return (
          <div key={post.id} className="post">
            <Link to={`/post/${post.id}`}>{post.title}</Link>
            <p>{post.text}</p>
            <div>
              {post.comments.map(comment => {
                return (
                  <div>
                    <Link to={`/post/${post.id}/@${[comment.id]}`}>
                      {comment.id}
                    </Link>
                  </div>
                );
              })}
            </div>
          </div>
        );
      });
    } else {
      return <h4>Loading...</h4>;
    }
  };

  render() {
    return <div>{this.createPostList()}</div>;
  }
}

const mapStateToProps = state => {
  return {
    posts: state.posts
  };
};

export default connect(mapStateToProps)(Posts);

Upvotes: 1

Views: 1403

Answers (2)

Winchester
Winchester

Reputation: 490

Use %23 as a hash sign, should definitely solve it.

More information about it: https://en.wikipedia.org/wiki/Percent-encoding

Here is a forked from you, that I use %23 to represent #

https://codesandbox.io/s/scrollintoview-with-refs-and-redux-z8pz8

Upvotes: 0

frogatto
frogatto

Reputation: 29285

Anything after # in a URL string is called hash. You can access the hash for a given location using location.hash. So in your routes you won't need to mention :hash. You should instead read the hash through the location object injected to the component by the Route component.

Your Route:

<Route path="/post/:id" component={Post} />

To read hash in Post component:

class Post extends React.Component {
    render() {
        const {location} = this.props;
        console.log(location.hash);
        ...
    }
}

Upvotes: 1

Related Questions