I have a React application running in production. When i am on, lets say /contacts page, an API call is made and if it returns a 404, i redirect the user to an error page ( /error ).
The redirection is happening to /error. I can see it in the url. But the issue is that the page rendered is a blank page. I don't know why. Please note I see one error in such scenario 'ChunkLoadError: Loading chunk 16 failed'
Below is the main pieces of code I have.
// In the index.js
import React, { useEffect, Suspense } from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import { createBrowserHistory } from "history";
const Contact = React.lazy(() => import("./pages/Contact"));
const Error = React.lazy(() => import("./pages/Error"));
function App() {
const history = createBrowserHistory({
basename: process.env.PUBLIC_URL
});
return (
<Router basename={"LB"} history={history}>
<div>
<div>
<Suspense fallback={"Loading..."}>
<Route path="/contact" exact component={Contact} />
<Route path="/error" component={Error} />
</Suspense>
</div>
</div>
</Router>
);
}
export default App;
// Inside the Contact page
axios.get(url)
.then((response)=>{console.log('success')})
.catch((error)=>{props.history.push("/error");})
Any suggestions or reason why this is happening?
Related
My page is becoming unresponsive when I try to navigate using useNavigate or a Link in my component. After clicking a button or link, the url will change, and the javascript inside the target component will execute, but the page does not re-render. useNavigate works with other components in my app, so I'm not quite sure what the issue is. Any input would be appreciated!
Dashboard.js:
import { useNavigate, Link } from "react-router-dom";
const Dashboard = () => {
console.log("hello from dashboard");
let navigate = useNavigate();
return (
<div>
<Link className="pl-20" to="/test">
test
</Link>
</div>
);
};
export default Dashboard;
Test.js:
import React from "react";
const Test = () => {
console.log("hello from test page");
return <div>this is the test page</div>;
};
export default Test;
App.js:
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Dashboard from "./pages/Dashboard";
import Test from "./pages/Test";
function App() {
return (
<>
<Nav />
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/test" element={<Test />} />
</Routes>
</>
);
}
gif showing the issue
you gave pl-20 class on Dashboard. but not on Test component.
Please check.
Hei, I am trying to build a simple react app with a navigation feature. The main theme is I have 3 components, App, Test, and AppShell. App component is the default(Initial) component. And what I want is that Every time user goes to App component, my app will redirect to Test component.
The problem I am facing is that my redirection only works when I load the application the first time, after that my redirection is not working.
I am sharing my three components code below along with the index page!
Index page
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import React from 'react';
import ReactDOM from 'react-dom';
import {
BrowserRouter as Router,
Routes,
Route
} from "react-router-dom";
ReactDOM.render(
<Router>
<Routes>
<Route path='/' element={<App />} />
<Route path='/test' element={<Test />} />
</Routes>
</Router>,
document.getElementById('root')
);
function Test() {
return <h1>Test Me</h1>;
}
reportWebVitals();
App Component
import "./App.css";
import AppShell from "./components/core/appShell";
import { useNavigate } from 'react-router-dom';
export default function App(props) {
let navigate = useNavigate();
return <AppShell {...props} navigate={navigate} />;
}
App shell component
import React, { Component } from 'react';
import { Outlet } from "react-router-dom";
class AppShell extends Component {
componentDidMount() {
this.props.navigate('/test');
}
render() {
return (
<div>
<h1>This is app shell</h1>
<Outlet />
</div>
);
}
}
export default AppShell;
I thought the problem is lies within component hooks, so I tried to implement the redirection inside the constructor too, but nothing is working for me!
The basic business problem I am trying to solve here is - A user will be redirected to a login page, every time he/she tries to browse another page regardless of valid login(valid user) could be based on the valid token on local storage
Could anyone say, What I am doing wrong?
Authentication with regards to protected routes is actually pretty trivial in react-router-dom v6
Create a wrapper component that accesses the auth context (local state, redux store, local storage, etc...) and based on the auth status renders an Outlet component for nested routes you want to protect, or a redirect to your auth endpoint.
Example AuthWrapper:
const AuthWrapper = () => {
const location = useLocation();
const token = !!JSON.parse(localStorage.getItem("token"));
return token ? (
<Outlet />
) : (
<Navigate to="/login" replace state={{ from: location }} />
);
};
Uses:
useLocation hook to grab the current location user is attempting to access.
Outlet component for nested protected routes.
Navigate component for declarative navigation, sends the current location in route state so user can be redirected back after authenticating.
Example Usage:
<Router>
<Routes>
<Route element={<AuthWrapper />}>
<Route path="/" element={<App />} />
</Route>
<Route path="/login" element={<Login />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</Router>
Login - In the authentication handler, once authenticated, set the localStorage and navigate to the location that was passed in route state.
function Login() {
const { state } = useLocation();
const navigate = useNavigate();
const { from = "/" } = state || {};
const login = () => {
localStorage.setItem("token", JSON.stringify(true));
navigate(from);
};
return (
<>
<h1>Test Me</h1>
<button type="button" onClick={login}>Log In</button>
</>
);
}
I have tried to decouple my components a bit more and I ran into this weird bug. I obscured the other general imports. All components import properly and work.
What happens is I land on "/", then I click a button to navigate to dashboard it's a blank page (the URL did change). Then I hit refresh in my browser and the correct component displays. This also happens if I go back to my landing page; it's blank until I refresh.
In my app component
import history from './services/history';
import Routes from './routes';
function App() {
return (
<Router history={history}>
<Routes />
</Router>
);
my history component (super simple)
import { createBrowserHistory} from 'history';
const history = createBrowserHistory();
export default history;
and finally my routes:
import Landing from "../pages/landing/landing.page"
import Dashboard from "../pages/dashboard/dashboard.page.jsx"
export default function Routes() {
return (
<Switch>
<Route path="/" exact component={Landing}/>
<Route path="/dashboard" component={Dashboard}/>
</Switch>
);
Here is my landing page, which I click the button to navigate to "/dashboard"
import { Link } from "react-router-dom";
function Landing () {
return (
<div class="landing-container">
<Link to="/dashboard"><button> Setup Tests </button></Link>
</div>
)
}
export default Landing;
It looks like you're now using Router from react-router-dom. From my understanding, you have to import BrowserRouter in terms of browser use. So your code would look like:
import { BrowserRouter } from "react-router-dom";
function App() {
return (
<BrowserRouter history={history}>
<Routes />
</Router>
);
}
I am having a bit of an issue with React Router that I can not seem to figure out. It does not go back to the very last page visited, rather the first page it loaded. Here is an example.
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import PrivateRoute from './utils/auth/PrivateRoute';
<Router>
<PrivateRoute exact path="/dashboard" component={DashboardView} />
<PrivateRoute exact path="/games" component={Games} />
<PrivateRoute
exact
path="/viewgame/:id*/"
component={SingleGameView}
/>
</Router>
When you go to /dashboard, you can click to view a games list that takes you to /games. You can then click on a game to see a single view of it, which takes you to /viewgame/:id*
Like so: /dashboard -> /games -> /viewgame/:id*
When you click on a game and are taken to /viewgame/, and then decide to click back in the browser, it takes me back to /dashboard instead of taking me back to /games. It is skipping over the last visited page, and taking me back to the first loaded page. I can send someone back to a route by setting up my own 'click to go back' button, but I need the browsers actual back and forward button to do this.
PrivateRoute is a HOC I setup to check to make sure the user accessing the route is authenticated or not. Otherwise they are booted. In case that could be the issue here is that component:
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
//Utils - Auth
import { userAuth } from '../../../authentication/authentication';
const { isAuthenticated } = userAuth;
//Checks if a user isAuthenticated. If so, it renders the passed in secure component. If not, it renders a redirect to /signin
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props =>
isAuthenticated() ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: '/signin',
state: { from: props.location }
}}
/>
)
}
/>
);
export default PrivateRoute;
Here’s a snapshot of the PrivateRoute props when it’s rendered a component:
You can achieve this by calling goBack() function in history object inside withRouter().
import React from 'react';
import { withRouter } from 'react-router-dom'
export default withRouter(({ history }) => {
return (
<div>
<button onClick={() => history.goBack()}>BACK</button>
</div>
)
});
You can simply use the useHistory hook from react-router-dom
import { useHistory } from "react-router-dom";
const history = useHistory();
...
<div onClick={ ()=>history.goBack() }>Back </div>
Remove 'exact' from your routes props.
I wanna open a popin inside a route, and I wanna add an hash to the url.
For example before onClick https://www.example.com/home after onClick https://www.example.com/home#send-me-an-email
Well it works but React Router rerender the whole route.
Am I doing something wrong with React Router ? Let's see my code below (I simplified the things)
index.jsx I am using BrowserRouter like everybody
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import App from './App';
const render = Component => {
ReactDOM.render(
<Router>
<Component />
</Router>,
document.getElementById('root')
);
};
render(App);
App.jsx I am using withRouter because I am gonna need history and location somewhere else
import React from 'react';
import { Route, Switch, withRouter } from 'react-router-dom';
import Header from './components/Header';
import Footer from './components/Footer';
import Home from './views/Home';
const App = ({ ...props }) => {
return (
<Header />
<section>
<Switch>
<Route exact path={"/"} component={() => <Home {...props} />} />
<Route path={"/home"} component={() => <Home {...props} />} />
</Switch>
</section>
<Footer />
);
};
export default withRouter(App);
Home.jsx unfortunately when I do this.props.history.push({ hash: 'send-me-an-email' }) it will rerender the route component Home, no good
...
render() {
<div>
<button onClick={() => this.props.history.push({ hash: 'send-me-an-email' })}>
Send me and email
</button>
<Popin
isOpened={this.state.isPopinOpened}
handleClose={() => this.props.history.push({ hash: '' })} />
</div>
}
...
How not to make a rerender just because I added a hash to te same url ? Cheers.
Simply rely on vanilla JS:
window.history.pushState("object or string", "Title", "/home#send-me-an-email");
This will add an hash/route without rendering or reloading anything.
I also wanted to add a #hash to the URL without triggering a re-render.
I simply used the useNavigate() hook from react-router-dom v6.
const navigate = useNavigate();
navigate('#my-fancy-hash');
Then, I read this hash with:
const { hash } = useLocation();
One thing to remember is that, at that point, the value of the hash variable would include the # character. When I had to actually use it, I simply stripped it out with:
hash.slice(1)
That should give you the proper value. I hope it helps!