How to avoid 404 page in react-router? - javascript

I'm working on a simple example using React Router.
I created it using create-react-app
On a local server, each link goes well
ex) localhost:3000/login, localhost:3000/ product, etc.
After deploying to my domain, I get a 404 error when I enter my link.
ex) myDomain.com/login, myDomain.com/product
It looks good on the local server, so I think there's no problem with the source code.
Then, I received an answer to redirect to the index.html page when the 404, 403 ... etc page appears
Are localhost:3000 and localhost:3000/index.html the same?
On the main page (localhost: 3000 or myDomain.com),
is well rendered.
In index.html (localhost: 3000 / index.html or myDomain.com/index.html)
it only renders up to h1 tag above {Home}. Is something wrong from here?
Please help me T.T
App.js
class App extends Component{
render(){
return (
<div className="App">
<Header/>
<h1>asd</h1>
<h1>asd</h1>
<Route exact path = "/" component = {Home}/>
<Route path = "/about" component = {About}/>
<Route path = "/event" component = {Event}/>
<Route path = "/qna" component = {QnA}/>
<Route path = "/login" component = {Login}/>
<Route path = "/join" component = {Join}/>
<Route path = "/product" component = {Product}/>
</div>
);
}
}
export default App;
Root.js
const Root = () => {
return (
<BrowserRouter>
<App/>
</BrowserRouter>
);
};
export default Root;

You can wrap your route components in a switch component and render a default component if none match like below.
<Switch>
<Route exact path = "/" component = {Home}/>
<Route path = "/about" component = {About}/>
<Route path = "/event" component = {Event}/>
<Route path = "/qna" component = {QnA}/>
<Route path = "/login" component = {Login}/>
<Route path = "/join" component = {Join}/>
<Route path = "/product" component = {Product}/>
<Route component={NoMatch} />
</Switch>
Obviously you'd change the NoMatch component with whatever you'd want your default component to be.

You should add the basename to the BrowserRouter component in the root
ReactDOM.render(
<BrowserRouter basename='/My-App/'>
<React.StrictMode>
<App />
</React.StrictMode>
</BrowserRouter>
,
document.getElementById('root')
);
Also, you should make sure in 404 cases you are redirected to index.html because it's a SPA and everything is happening there, you do this by simply replacing this line with "build" script in package.json
"build": "react-scripts build && cp build/index.html build/404.html",

I don't think this is your react app issue, rather it's how your app is deployed.
I hope you have deployed your app using production build (using npm run build).
If so, this is most likely that your web server is not redirecting to the right entry.
You need to tell your web server(nginx or caddy whatever you are using) to point to /index.html when hitting 404. Here is a simple config for nginx.
https://www.barrydobson.com/post/react-router-nginx/

Related

Creating dynamic Link with some text before it

I was building a search engine for custom project.
There I have a search bar from where user can search.
When the user searches, I want the given link to work as it works in case of google
www.google.com/ search? queryRelatedInfo
Notice the search? and then whatever query/parameter/ID
for this I tried something like this in
import React, {Component} from 'react';
import {
BrowserRouter,
Route,
Switch,
Redirect,
} from 'react-router-dom';
import SearchScreen from "./container/searchScreen.js"
import HomeScreen from "./container/home.js";
class route extends Component {
render () {
return (
<BrowserRouter>
<div>
<Switch>
<Route path ="/" exact render ={(props) => <HomeScreen {...props}/>} />
<Route path ="/search?:id" exact render ={(props) => <SearchScreen {...props}/>} />
</Switch>
</div>
</BrowserRouter>
)
}
}
export default route
Notice, <Route path ="/search?:id" above.
Unfortunately this didn't worked out.
I understand that <Route path ="/:id" works but how can i make <Route path ="/search?:id to work i.e how can I make some link like http://localhost:3000/search?9e9e to work
I think this is related with historyApiFallback. That parameter;
(https://webpack.js.org/configuration/dev-server/#devserver-historyapifallback)
When using the HTML5 History API, the index.html page will likely have to be served in place of any 404 responses. devServer.historyApiFallback is disabled by default. Enable it by passing:
module.exports = {
//...
devServer: {
historyApiFallback: true
}
};
Your react app is a single page application. So all path except home path actually is an virtual path, they are not physically exist. The paths must routed to home path. So react-router can manage.
you don't need to put the path like this /search?:id, just put it search
<Route path ="/search" exact render ={(props) => <SearchScreen {...props}/>} />
then inside your SearchScreen component, get the value of search parameter from the URL, check this issue will help.
after the user make search, pass the value like this /search?s=value_here

Hash Router back button with React Router v4

I'm using HashRouter to setup my App like so:
import {HashRouter as Router, Route, Switch, Link} from 'react-router-dom';
const Routing = () => (
<Router>
<div>
<Route exact path ="/" component = {App} />
<Route path ="/about" component = {About} />
</div>
</Router>
)
It works great, but when I click a link to go to /about and then hit the back button nothing happens. How do I make it so my internet browser's back button will take me back to the previous page? The app is built using create-react-app if that makes a difference.
Use Switch
Switch is unique in that it renders a route exclusively. In
contrast, every Route that matches the location renders inclusively.
This means that the way you are doing it all routes are being rendered because they match.
If the URL is /about, then About, User, and NoMatch will all
render because they all match the path. This is by design, allowing us
to compose Routes into our apps in many ways, like sidebars and
breadcrumbs, bootstrap tabs, etc.
Now, if we're at /about, Switch will start looking for a matching
Route. Route path="/about" will match and Switch will stop
looking for matches and render About
Your code should look like this
import {HashRouter as Router, Route, Switch, Link} from 'react-router-dom';
const Routing = () => (
<Router>
<Switch>
<Route exact path ="/" component = {App} />
<Route path ="/about" component = {About} />
</Switch>
</Router>
)

Express React Router Internal Server Error When Linked Directly

I am using an express server to serve a create-react-app build.
server.js
// Express only serves static assets in production
if (process.env.NODE_ENV === 'production') {
server.use(express.static('client/build')); // <--- this might be causing my problem, how to make work?
}
var api = require('./routes/api');
var email = require('./routes/email');
// Define API routes before the *
server.use('/api', api);
server.use('/email', email);
server.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
app.js
class App extends Component {
render() {
return (
<Router history={browserHistory}>
<Route component={Container}>
<Route path="/" component={Main} />
<Route path="/catalog" component={Catalog} />
<Route path="/product/:productId" component={ProductPage} />
<Route path="/faq" component={Faq} />
<Route path="/blog" component={Blog} />
<Route path="/inquiry" component={Inquiry} />
<Route path="/cart" component={Cart} />
</Route>
</Router>
);
}
}
export default App;
Edit:
Updated my server.js file to show relevant code. I think the issue lies in using express.static('client/build'), but I'm not quite sure what to change it to in order to fix my routing issues.
/Edit
This works perfectly fine in Dev and Heroku where clicking links in the app go from route to route. For example being at the root, I can click on a link to "https://thesite.com/catalog" and the app navigates there as with any other route.
However, if I were to copy the URL above and paste it into a new tab/browser, I get a 500 Internal Server Error. This would mean the user cannot bookmark any page other than the root. Or if another site linked to a specific route on my page it would show a 500 error. Refreshing in a page that isn't "/" returns a 500 error. Does anyone know how to fix this?
Figured it out. I needed to add a universal route getter for express.static('client/build').
if (process.env.NODE_ENV === 'production') {
server.use(express.static('client/build'));
server.use('*', express.static('client/build')); // Added this
}

ReactJs cannot acess nested route

I have an issue using nested routes with react-router.
Here is my code (two simple react components, routes file to access comp1/comp2) :
House.js
export default connect(st => st)(class House extends React.Component {
render() {
return (
<div>
{this.props.children}
</div>
);
}
})
Window.js
export default connect(st => st)(class Window extends React.Component {
render() {
return (
<div >
hey hey
</div>
);
}
})
routes.js
export const routes = (
<Router history={ history }>
<Route path="/house" component={House}>
<Route path="/house/window" component={Window} />
</Route>
</Router>
);
When I redirect to "/house/window" programmatically, I can access the route and the page shows "hey hey".
If I want to access the url directly :
localhost:8080/house/window
It shows a blank page and a console error :
Request URL:http://localhost:8080/house/window
Request Method:GET
Status Code:304 Not Modified
And then :
GET http:// localhost:8080 /house/js/bundle.js (404)
Also, http:// localhost:8080 /house/ (with trailing slash) shows the same error.
I really don't understand this weird redirection http:// localhost:8080 /house/js/bundle.js
I'm probably doing something wrong, but after crawling stackoverflow, I still can't see it.
I found the issue : my bundle.js script included in index.html was included with a relative path 'js/bundle.js' so I changed it for '/js/bundle.js'.
Sadly, it didn't make any problem until I wanted to nest some routes.
Nested routes cannot have parent path included in path attribute:
export const routes = (
<Router history={ history }>
<Route path="/house/" component={House}>
<Route path="window" component={Window} />
</Route>
</Router>
);

react-router 2.0 doesn't route

I have this simple code that doesn't work. I took it from the react-router project page and modified slightly for it to look a bit better.
Setup
I have several very simple react components:
var IndexPage = React.createClass({
render(){
return (<h1>Index Page</h1>);
}
});
var AboutPage = React.createClass({
render(){
return (<h1>About page</h1>);
}
});
var NotFoundPage = React.createClass({
render(){
return (<h1>Not found page</h1>);
}
});
Also I have made a setup of react router:
var ReactRouter = require('react-router');
var Router = ReactRouter.Router;
var Route = ReactRouter.Route;
var BrowserHistory = ReactRouter.browserHistory;
var Render = ReactDOM.render;
And that's how I use react router 2.0.
Render((
<Router history={BrowserHistory}>
<Route path="/" component={IndexPage}>
<Route path="about" component={AboutPage}/>
<Route path="*" component={NotFoundPage}/>
</Route>
</Router>
), document.body)
I use BrowserHistory (not HashHistory) to avoid hash in urls.
My server is raised under IIS 10 (Windows 10) on 8080 port.
Problem
http://localhost:8080/
goes to IndexPage component. This is correct.
http://localhost:8080/about
goes to IIS 404 error page. Routing doesn't work in this case
http://localhost:8080/ttt
goes to IIS 404 error page again.
So the router doesn't see this nested paths that go after /. And it doesn't even care about whether they are correct or not.
What can cause such a strange behavior?
Thanks in advance!
Update
I've found out that the next string solves the problem with a client routing:
{this.props.children}
This is the fixed code:
var IndexPage = React.createClass({
render(){
console.log('index page render');
return (<div>
<h1>Index Page</h1>
<Link to={ '/about' }>about</Link>
{this.props.children}
</div>);
}
});
Is your server configured to map all application-paths to your index.html? You should never get a IIS 404 if your server would map all path to your index file, as it always would deliver this one.
React-router is a client-side routing solution(also works in server side, but it seems you are using .Net as the server side handler).
You can try this(Link from React-Router):
<Link to={ pathname: 'about' }>
about
</Link>
Put it in the index page's component, and click the link, the react-router will work.
Update:
{this.props.children} ref to the inner component(AboutPage, NotFoundPage).
If you change code to that:
<Route path="/" component={IndexPage} />
<Route path="/about" component={AboutPage}/>
<Route path="*" component={NotFoundPage}/>
It will works.(remove the {this.props.children} in IndexPage if there is no nesting routes).
I was able to solve my issue linking directly to URLs by adding --history-api-fallback to my webpack-dev-server command.
Setting this flag prompts webpack-dev-server to serve the index page instead of 404. The index page will then route correctly on the client side.

Categories