I have...
Node.js/express server which serves files when requests are made to certain routes.
React pages that makes calls to the back-end requesting data to populate the pages.
I'm using react-router v4 on the front end. Whenever I navigate to a route that is NOT at the exact path AND reload the page, I get a 404 error. I understand why this isn't working; the browser makes a request to a path handled by react-router, and since it doesn't find that route on the server, I get 404.
I'm seeking for a solution to this problem.
// BrowserRouter imported as Router
<Router>
<Route exact path='/main' component={Main} />
<Route path='/sub1' component={SubOne} />
<Route path='/sub2' component={SubTwo} />
</Router>
When I go to /main
in the browser, <Main />
is rendered. Say that inside <Main />
, there are links to /sub1
and /sub2
respectively. I click on /sub2
. Component and page content renders without fail. Then I refresh page, either by accident or intentionally (say component Sub2 lifts state up to Main).
How do I avoid getting 404 after this refresh? How do I get the page/component where "I was" rendered after a refresh if I'm using React-Router?
Use a wildcard placeholder to handle 404 page not found in React router, e.g. <Route path="*" element={<PageNotFound />} /> . A route that has an asterisk path * serves as a catch all route. It only matches when no other routes do.
Routing to the 404 Page You specify the URL path and the element you want to render at that route. The 404 page displays for paths that don't exist on the website. So, instead of specifying the path, use an asterisk (*). Using * renders the NotFound component for all the URLs not specified in routes.
import React from 'react'; function App() { function refreshPage() { window. location. reload(false); } return ( <div> <button onClick={refreshPage}>Click to reload!
I had the same issue you're having about 2 months ago. I had very little knowledge about server-side rendering with React. I got confused on the general concept of it. However, I didn't want to use the create-react-app cli. I wanted to use my own boilerplate. Upon doing research, I found out that I had to configure my webpack to handle my 404 reloading fallbacks.
Here is my current webpack setup:
Please note, only pay attention to the historyApiFallback: true
that allows you to refresh your page without throwing a 404 error if you're using v4. In addition, i forgot to mention that this requires webpack-dev-server to work.
const webpack = require('webpack');
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const HtmlWebPackPlugin = require('html-webpack-plugin');
var browserConfig = {
devServer: {
historyApiFallback: true,
proxy: {
"/api": "http://localhost:3012"
}
},
entry: ['babel-polyfill', __dirname + '/src/index.js'],
output: {
path: path.resolve(__dirname + '/public'),
filename: 'bundle.js',
publicPath: '/'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
query: {
presets: ['react', 'env', 'stage-0']
}
}
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: './public/index.html',
})
]
}
var serverConfig = {
target: 'node',
externals: [nodeExternals()],
entry: __dirname + '/server/main.js',
output: {
path: path.resolve(__dirname + '/public'),
filename: 'server.js',
publicPath: '/'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
query: {
presets: ['react', 'env', 'stage-0']
}
}
}
]
}
}
module.exports = [browserConfig, serverConfig]
The reason you got 404 is refreshing the page poses network roundtrip to hit the server, while react-router is a client-side routing library, it doesn't handle server-side routing.
when the user hits the refresh button or is directly accessing a page other than the landing page, e.g. /help or /help/online as the web server bypasses the index file to locate the file at this location. As your application is a SPA, the web server will fail trying to retrieve the file and return a 404 - Not Found message to the user.
Since you're using an Express server, connect-history-api-fallback(Express middleware) can be used to proxy all received requests(including unknown ones, /sub2 in your case) through your index page. Then reboot your SPA and route to /sub2 on the client by react router.
If you're using webpack-dev-server for local development, it will be as simple as turning on devServer.historyApiFallback.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With