0

So I built a website using React but none of the routes can be accessed directly. The server that is hosting my react code is CPanel if that matters.

I understand that for a route, such as www.website.com/about, the "/about" does not actually exist on the server. React dynamically updates the browser URL as the user is clicking on the app and "navigates" the webpages. If a user tries to access the about route directly, the server will not know what to do unless I do some extra work.

But there must be a way to be able to type "www.website.com/about" (with a React based website) directly into the browser and access that page directly, right?

I read this and this, both mentioning a catch all solution. I think I got half of that solution so far with my "htaccess" file (for instance, if you type www.website.com/about into the browser url, it will just redirect to the home page of my site).

Now I want my code to be able to parse the browser URL and know to render the correct page/component, rather than just redirect to my home page. My confusion stems from the following (quoted from the second link):

Catch-all

If you already have a server you’re using, this is probably your best bet. The main idea here is that you redirect all of your server requests to /index.html. The outcome is similar to Hash History. Any request that is made to your server will respond with the index page (and then fetch any JS resources you need), React Router will then take over and load the appropriate view. The actual code for this varies on which type of server you have.

(emphasis mine)

So my .htaccess file does technically respond to the index.html page. Now I want React Router to "take over and load the appropriate view". Is this an issue with my code or is this something related to my server?

For reference, the following contains the contents of my .htaccess file. (apologies ahead of time, I don't know anything about how to write htaccess files, its all copied from random tutorials I found) :

RewriteEngine On 
RewriteBase /
RewriteCond %{SERVER_PORT} 80
RewriteCond %{HTTP_HOST} ^(www\.)?wiseattend\.com
RewriteRule ^(.*)$ https://www.wiseattend.com/$1 [R,L]
RewriteCond %{THE_REQUEST} /([^.]+)\.html [NC]
RewriteRule ^ /%1 [NC,L,R]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^ %{REQUEST_URI}.html [NC,L]
RewriteRule ^index\.html$ / [R=301,L]

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

And here is the App.js file from my react code:

import React, { useState, useLayoutEffect, useEffect } from 'react';
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
import { history } from './history';


// components
// pages
import Home from './pages/Home';
import Privacy from './pages/Privacy';
import Contact from './pages/Contact';


const App = () => {

  return (
    <div className="app">
      <Router history={history}>
        <NavBar />
        <Switch>
          <Route exact path="/" render={(props) => <Home {...props} />} />
          <Route path="/privacy" render={(props) => <Privacy {...props} />} />
          <Route path="/contact" render={(props) => <Contact {...props} />} />
        </Switch>
        <Footer />
      </Router>
    </div>
  );
}

export default App;

And here is my index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { BrowserRouter } from 'react-router-dom';

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);

I feel like React Router should be smart enough to parse a URL and render the actual components that I need (with my .htaccess file serving the index.html), and that it is likely I am missing something in my code that will accomplish this. I feel that perhaps it has something to do with my history object but I am not sure.

Any help would be greatly appreciated.

im2wddrf
  • 551
  • 2
  • 5
  • 19
  • 1
    You really only need a single `Router` for your app. Try removing the root-level one wrapping `App` since the one `App` is rendering is receiving your history object. I suspect it is the dual router contexts that cause issue when the page is reloaded since the route data is in the inner router context and the outer router has nothing. This is just a hunch though. – Drew Reese Nov 10 '20 at 07:16
  • I appreciate the tip but I don't think it worked. I replaced the `` wrapper in the `index.js` file with just the `` component. Still didn't work when I uploaded the new build to cpanel. When I refresh on 'www.website.com/about' it still redirects me to the home page per the `.htaccess` file. – im2wddrf Nov 10 '20 at 07:22

1 Answers1

3

So I fixed this by fixing my .htaccess file. I'll give the contents of my file (got it from this essential tutorial here) then explain why I think it fixed my issue.

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

So the incorrect behavior that I was encountering was that my website was rerouting all endpoints to the home page. So if I were to manually refresh on or (manually type into the browser) www.website.com/about, the browser would just send it to the homepage www.website.com. Instead, I wanted for React to be able to render all the components for the www.website.com/about

A few things that I learned along my journey that was critical for arriving at my solution:

  • www.website.com/about does not exist on the server. Therefore, you need to prompt your server to know to serve the index.html for whichever route the server gets a request for: whether it is /, /about, or /anyrandomthing, your server should know to serve the index.html file always, and React should handle the rest. In my case, due to the server I was using, the .htaccess file is where that logic is implemented.

  • React Router dynamically updates the browser URL, but it is not making server requests. So, when the user clicks on the "About Us" button on my homepage, it is not actually making a server request—all it is doing is prompting the React code to render the Route component when appropriate and updating the browser url to make it appear that the user is navigating web pages.

My issue was that my old .htaccess was encountering unknown routes and fixing the browser url to refer the base (/about does not exist on the server, so it was changing the browser url to /). Instead, I needed to modify my .htaccess file to serve index.html for any route and preserve the route as well, so that React Router can render the appropriate components.

Basically:

Wrong Method: /about --> fix the browser url to /, serve index.html

Correct Method: /about --> fix the browser url to / (React Router will see the url and respond appropriately), serve index.html

im2wddrf
  • 551
  • 2
  • 5
  • 19