Search code examples
reactjs.htaccessreact-router

React Router v5: 404 when use url directly or refresh page on route different from "/"


I use React Router v5:

"react-router-dom": "^5.2.0",
"react-router-hash-link": "^2.4.3",

and I need to allow page refresh and allow using direct url. So, for now, when I try to refresh page with route other than "/", I got 404. Also, when I try to use direct link in browser adress bar, I also got 404. How I tried to fix this:

  1. Tried to use HashRouter instead of BrowserRouter (no luck)

  2. Since I host my app on apache web-server, I added .htaccess with next rules:

    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-l
    RewriteRule . /index.html [L]
    
    

not helped.

What I want to achieve: when I am, for example, on route /test/route, I want to load component, related to this route when refresh page or try to open this page directly in another tab by localhost/test/route url.

Could you help me to achieve this ?

P.S. I also added <base href="/" /> to the index.html. But this not help also.

UPDATED: this is how my routes looks like:

<Switch>
  <Route exact path="/">
    <MainPage />
  </Route>
  <Route exact path="/topic">
    <TopicPage />
  </Route>
  <Route exact path="/about">
    <AboutPage />
  </Route>
  ...
</Switch>

Solution

  • Well, I finally fixed the issue. First of all, I replaced BrowserRouter with HashRouter as it suggested in another answers on stackoverflow.

    But I still experienced redirecting to "/". So, I added useEffect with timeout to redirect to needed route:

    const history = useHistory();
    const location = useLocation();
    
    useEffect(() => {
        setTimeout(() => {
            history.push(location.pathname);
        }, 100);
    }, []);
    

    This works for me. It works when refreshing the page on selected route. And this works when using url directly in browser address bar.

    P.S. no need to use .htaccess with this solution.

    UPDATED: I added some code to make redirect work with hash.

    useEffect(() => {
        setTimeout(() => {
            history.push(location.pathname);
            const hash = location.hash.trim();
            if (hash) {
                window.location.href = `#${location.pathname}${location.hash}`;
    
                const id = hash.replace("#", "");
                const element = document.getElementById(id);
                if (element) {
                    // in case if scroll has offset (20 is offset)
                    const elementPosition = element.offsetTop - 20;
                    window.scroll({
                        top: elementPosition,
                        left: 0,
                        behavior: "smooth"
                    });
                }
            }
        }, 100);
    }, []);