How do I navigate to a specific page with url in React?
I realized I've used CRA in the past and haven't really tackled this specifically.
Currently I'm rendering ReactDOM with BrowserRouter and Switch with exact path in Routes
// index.jsx
/* eslint-disable import/extensions */
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './app/App.jsx';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'),
);
// App.jsx
import React from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import Header from '../components/Header';
import HomePage from '../pages/Home';
import PlansPage from '../pages/Plans';
import NotFoundPage from '../pages/NotFound';
const App = () => (
<BrowserRouter>
<Header />
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/plans" component={PlansPage} />
<Route component={NotFoundPage} />
</Switch>
</BrowserRouter>
);
export default App;
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
module.exports = {
devtool: false,
module: {
rules: [
{
test: /\.m?(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.scss$/,
use: [{
loader: 'style-loader',
options: {
sourceMap: true,
},
}, {
loader: 'css-loader',
options: {
sourceMap: true,
},
}, {
loader: 'sass-loader',
options: {
sourceMap: true,
},
}],
},
],
},
entry: './src/index.jsx',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'index_bundle.js',
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: './index.html',
}),
new webpack.SourceMapDevToolPlugin({}),
],
};
Navigating to http://localhost:8080/plans leads to a page with Cannot GET /plans. However, clicking on a Link element navigates to that plans page without an issue.
Yeah since you're using webpack Dev Server all you have to do is add historyApiFallback=true and it'll fix you issue. You're essentially telling all routes to fall back to your index.html file. Hope that helped.
Related
I am currently trying to deploy my react app created with Webpack. I am using react router for routing and everything works fine in dev mode, but when I am creating the production version of my web app routing works too at first but when I refresh the page I get the following
Not found
I also don't know if this is caused by webpack.
This is my webpack.common.js (settings that are similar between production and dev version)
const path = require("path");
module.exports = {
context: __dirname,
entry: {
main: "./src/index.js",
vendor: "./src/vendor.js"
},
module: {
rules: [
{
test: /\.html$/,
use: ["html-loader"]
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
{
test: /\.(jpg|png)$/,
use: {
loader: "file-loader",
options:{
name: "[name].[hash].[ext]",
outputPath:"imgs"
}
},
},
{
test:/\.svg$/,
use: ['#svgr/webpack']
},
{
test: /\.(ttf|eot|woff|woff2)$/,
exclude: /node_modules/,
use: {
loader: "url-loader",
},
},
],
},
};
This is my webpack.prod.js (production version of webpack):
const path = require("path");
const common = require("./webpack.common");
const { merge } = require("webpack-merge");
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserPlugin = require("terser-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = merge(common, {
context: __dirname,
mode: "production",
output: {
path: path.resolve(__dirname, "dist"),
publicPath: "/",
filename: "bundle.[contentHash].js",
},
optimization: {
minimizer:[
new OptimizeCssAssetsPlugin(), new TerserPlugin()
]
},
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
],
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({ filename: "[name].[contentHash].css" }),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "public/template.html"),
// favicon: "./src/App/assets/Logo.png",
filename: "index.html",
minify:{
removeAttributeQuotes: true,
collapseWhiteSpaces: true,
removeComments: true,
}
}),
],
})
This is the main react file that provides the routes:
import Projects from "./pages/Projects/projects.jsx";
import ContentSwitch from "./pages/Content/ContentSwitch/ContentSwitch.jsx";
import Contact from "./pages/Contact/contact.jsx";
import Foyer from "./pages/Foyer/foyer.jsx";
import Login from "./pages/Login/login.jsx";
import Error from "./pages/Error/error.js";
import UgBar from "./shared/bar/bar.jsx";
import "./scss/App.scss";
import React, {
useRef,
useState,
useCallback,
useLayoutEffect,
useContext,
} from "react";
import { Route, Switch } from "react-router-dom";
import { AnimatePresence } from "framer-motion";
import { SearchProvider } from "./context/SearchContext.js";
import { BlurProvider } from "./context/BlurContext.js";
function App() {
return (
<div>
<SearchProvider>
<BlurProvider>
<UgBar />
<AnimatePresence>
<Switch className="ug-switch">
<Route exact path="/" component={Foyer}></Route>
<Route path="/projects" component={Projects}></Route>
<Route path="/content" component={ContentSwitch}></Route>
<Route path="/contact" component={Contact}></Route>
<Route path="/login" component={Login}></Route>
<Route path="*" exact={true} component={Error}></Route>
</Switch>
</AnimatePresence>
</BlurProvider>
</SearchProvider>
</div>
);
}
export default App;
Thank you and stay safe!
What kind of server are you using?
I had this problem using nginx. In the sites-available file the line I had to fix was
try_files $uri $uri/ /index.html =404;
in the server block. Now it works.
import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import { history } from './history';
import Login from './components/Login';
import Home from './components/Home';
import NotFound from './presentation/NotFound';
import MainContent from './components/MainContent';
import Overview from './components/Overview';
export default () => {
return(
<Router history ={history}>
<Switch>
<Route path="/" component={Login} exact />
<Home>
<Route path="/main" exact component={MainContent} />
<Route path="/admin/:id" exact component={Overview} />
</Home>
<Route component={ NotFound } />
</Switch>
</Router>
);
}
my webpack config is
const path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './src/main.js',
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js'
},
module: {
rules: [{
loader: 'babel-loader',test: /\.js$/,exclude: /node_modules/},
{
test: /\.s?css$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}, {
test: /\.(png|jpg|gif)$/,
use: [
'file-loader',
],
},{
test: /\.svg$/,
use: ['#svgr/webpack'],
}, {
test: /\.ttf$/,
loader: "file-loader?limit=10000"
}
]
},
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: path.join(__dirname, 'public'),
historyApiFallback: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
__CLIENT__: JSON.stringify(true),
__DEVELOPMENT__: true,
__DEVTOOLS__: true
}),
],
optimization:{}
};
So when i land on /main i.e. MainContent component it renders a ViewComponent which renders a list of admins and on click of an individual element of the list it gives the detailed view of the that element on the /admin/:id route which works fine.
but if i refresh or hit the url directly from the address bar, the
fonts' and the images' network request that were being rendered initially
from localhost:8080/somerandomid.ttf are now retrieved from
localhost:8080/admin/somerandomid.ttf throws a 400 bad request error and the styles change.
can anybody suggest how to rectify this error. i am calling a function and passing the id on click of an element from the list.
this.props.history.push('/admin/' + id);
and that ViewComponent is which renders the admin list is connected as export default withRouter(ViewComponent); to get this.props.history.push.
same goes with the image url too. localhost:8080/otherandomid.png is replaced and tried to get > from localhost:8080/admin/otherandomid.png and throws a 400 bad request error with no image
displaying.
You need to set up a base URL.
It can be done with HtmlWebpackPlugin:
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
__CLIENT__: JSON.stringify(true),
__DEVELOPMENT__: true,
__DEVTOOLS__: true
}),
new webpack.HtmlWebpackPlugin({
base: '/'
}),
],
Or directly in the <head> of your index.html file:
<base href="/">
Here's my App.jsx that's first mounted to the DOM:
import React, { Component } from 'react';
import Home from './Home.jsx';
import Representatives from './Representatives.jsx';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
export default class App extends Component {
constructor() {
super();
this.state = {value: ''};
}
render() {
return (
<Router>
<div>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/representatives" component={Representatives} />
</Switch>
</div>
</Router>
)
}
}
And here's the representative's component:
import React, { Component } from 'react';
export default class Representatives extends Component {
constructor() {
super();
this.state = {value: ''};
}
render() {
return (
<div>
Hello World!
</div>
)
}
}
It looks exactly like examples I've seen and my webpack config looks like other's I've seen in similar posts. Any help would be greatly appreciated, I'm at 4+ hours wracking my brain
Here's my webpack config:
const path = require('path');
const SRC_DIR = path.resolve(__dirname, './src');
const BUILD_DIR = path.resolve(__dirname, './public/');
module.exports = {
mode: 'development',
entry: path.resolve(SRC_DIR, 'index.jsx'),
output: {
filename: 'bundle.js',
path: BUILD_DIR,
publicPath: '/'
},
devServer: {
historyApiFallback: true,
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: [/node_modules/],
use: [{
loader: 'babel-loader',
options: { "presets": [
"#babel/env",
"#babel/react"
] }
}],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
]
}
}
I added the historyApiFallback: true, and publicPath: '/'
as recommended by another post here.
Here is the index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App/App.jsx';
ReactDOM.render(<App />, document.getElementById('root'));
router is not working.
localhost:3000/, localhost:3000/#/, localhost:3000/#/aa ==> all moves in home page.
index.js
import ReactDOM from 'react-dom'
import { BrowserRouter, Route, Switch } from 'react-router-dom'
ReactDOM.render(
<BrowserRouter>
<div>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/aa" component={Main}/>
</Switch>
</div>
</BrowserRouter>,
document.getElementById('app')
);
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const lunaRocketModulesPath = path.resolve(__dirname, 'luna-rocket');
module.exports = {
entry: [
'#babel/polyfill',
path.join(__dirname,'src/app','app.js')
],
output: {
path: path.join(__dirname,'build'),
filename: 'index.bundle.js'
},
mode: process.env.NODE_ENV || 'development',
resolve: {
alias: {
},
extensions: [
'.js',
],
},
devServer: {
contentBase: path.join(__dirname,'src')
},
module: {
rules: [
{
// this is so that we can compile any React,
// ES6 and above into normal ES5 syntax
test: /\.(js)$/,
// we do not want anything from node_modules to be compiled
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.(css|scss)$/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"sass-loader" // compiles Sass to CSS, using Node Sass by default
]
},
{
test: /\.(jpg|jpeg|png|gif|mp3|svg)$/,
loaders: ['file-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname,'src','index.html')
}),
]
};
how to move aa??? please help me.
i don't why router is not working.
and url in # is what is meaning in react??
if localhost:3000/aa--> devServer is working
if localhost:3000/#/aa ==> Home page
(React 16, babel7, wepack4)
I can't really identify was wrong here, but try removing the <Switch></Switch> around the routes and also <Route exact path="/aa" component={Main}/>
without exact this also matches the first route
Actually with /#/aa you are just routing towards / because # specifies an "Anchor", or a position on the page, and allows you to "jump" or "scroll" to that position on the page.
your Main will be available at localhost:3000/aa
hey guys having trouble with react-router, i keep getting this unexpected token you may need an appropriate loader to handle this file type on the line with <Router history={browserHistory}>. im not sure what is going on here any help would be appreciated!
thanks
import React from 'react'
import ReactDOM from 'react-dom'
import { Router, Route, browserHistory } from 'react-router'
import Products from './Products'
import Home from './Home'
document.addEventListener('DOMContentLoaded', function() {
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={Home} />
<Route path="/" component={Products} />
</Router>, document.getElementById('mount')
);
});
webpack.config
var path = require('path');
var config = {
context: path.join(__dirname, 'src/js'),
entry: [
'./main.js',
],
output: {
path: path.join(__dirname, 'www'),
filename: 'bundle.js',
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loaders: ['babel'],
},
],
},
resolve: {
root: [
path.join(__dirname, 'node_modules'),
],
},
};
module.exports = config;
.babelrc
{
"presets": ["es2015", "react"]
}
This isn't a React Router issue but instead is an issue with your JSX transpilation. Check your webpack.config.js file or your .babelrc file.