I recently deployed my site on to a work test server. When I was building everything locally it seemed to be working fine. However once I went ahead and deployed it, the site now auto refreshes none stop almost every second. I have gone through my code and the small changes I made and can't seem to find what the cause of the issue is and why the site on our work vps is now refreshing over and over again. I'm hoping someone might have some insight on this. I have gone ahead and posted my App.jsx, index.js, and Home.jsx below. Any insight on the matter would be really appreciated.
I should also note that I went back and moved everything back local to see if there is something I might have done before sending it to the server. It would seem when I run this locally there are zero issues. I've also tested this on multiple browsers and asked a few colleagues to take a look and it seems it continues to refresh every second for them too and on multiple browsers
App.jsx
import "./app.scss";
import Home from "./pages/home/Home";
import Register from "./pages/register/Register";
import Watch from "./pages/watch/Watch";
import Login from "./pages/login/Login";
import {
BrowserRouter as Router,
Switch,
Route,
Redirect,
} from "react-router-dom";
import { useContext } from "react";
import { AuthContext } from "./context/authContext/AuthContext";
const App = () => {
const { user } = useContext(AuthContext);
return (
<Router>
<Switch>
<Route exact path="/">
{user ? <Home /> : <Redirect to="/register" />}
</Route>
<Route path="/register">
{!user ? <Register /> : <Redirect to="/" />}
</Route>
<Route path="/login">{!user ? <Login /> : <Redirect to="/" />}</Route>
{user && (
<>
<Route path="/movies">
<Home type="movie" />
</Route>
<Route path="/series">
<Home type="series" />
</Route>
<Route path="/watch">
<Watch />
</Route>
</>
)}
</Switch>
</Router>
);
};
export default App;
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { AuthContextProvider } from "./context/authContext/AuthContext";
ReactDOM.render(
<React.StrictMode>
<AuthContextProvider>
<App />
</AuthContextProvider>
</React.StrictMode>,
document.getElementById("root")
);
Home.jsx
import Navbar from "../../components/navbar/Navbar";
import Featured from "../../components/featured/Featured";
import "./home.scss";
import List from "../../components/list/List";
import { useEffect, useState } from "react";
import axios from "axios";
const Home = ({ type }) => {
const [lists, setLists] = useState([]);
const [genre, setGenre] = useState(null);
const axiosInstance = axios.create({
baseURL: process.env.REACT_APP_API_URL,
});
useEffect(() => {
const getRandomLists = async () => {
try {
const res = await axiosInstance.get(
`lists${type ? "?type=" + type : ""}${
genre ? "&genre=" + genre : ""
}`,
{
headers: {
token:
"Bearer " +
JSON.parse(localStorage.getItem("user")).accessToken,
},
}
);
setLists(res.data);
} catch (err) {
console.log(err);
}
};
getRandomLists();
}, [type, genre, axiosInstance]);
return (
<div className="home">
<Navbar />
<Featured type={type} setGenre={setGenre} />
{lists.map((list) => (
<List list={list} />
))}
</div>
);
};
export default Home;
A new axiosInstance is created on every render, and it triggers useEffect change.
Move the axiosInstance creation out of the component.
const axiosInstance = axios.create({
baseURL: process.env.REACT_APP_API_URL,
});
const Home = ({ type }) => {
const [lists, setLists] = useState([]);
const [genre, setGenre] = useState(null);
// stuff
};
Does the route that contains the component refreshes infinitely?
That is because React Refresh causes component remount each time the state changes. In your case, you are creating an axios instance 1) not only not storing it in the useState ( you create it as a plain variable ), 2) but also on each component render;
That causes the React Refresh to go crazy. The reason why it works on local might be related to some Webpack stuff, but that doesn't matter much as you should configure axios differently anyways.
Solution:
Why not to set up default configuration that will be common for all the requests through the application?
import "./app.scss";
import Home from "./pages/home/Home";
import Register from "./pages/register/Register";
import Watch from "./pages/watch/Watch";
import Login from "./pages/login/Login";
import {
BrowserRouter as Router,
Switch,
Route,
Redirect,
} from "react-router-dom";
import { useEffect, useContext } from "react";
import { AuthContext } from "./context/authContext/AuthContext";
const App = () => {
useEffect( () => {
axios.defaults.baseURL = process.env.REACT_APP_API_URL;
}, [] )
const { user } = useContext(AuthContext);
return (
<Router>
<Switch>
<Route exact path="/">
{user ? <Home /> : <Redirect to="/register" />}
</Route>
<Route path="/register">
{!user ? <Register /> : <Redirect to="/" />}
</Route>
<Route path="/login">{!user ? <Login /> : <Redirect to="/" />}</Route>
{user && (
<>
<Route path="/movies">
<Home type="movie" />
</Route>
<Route path="/series">
<Home type="series" />
</Route>
<Route path="/watch">
<Watch />
</Route>
</>
)}
</Switch>
</Router>
);
};
export default App;
So that no instances are created, and defaults are configured correctly.
Then you use it like:
axios.post( '/someendpoint', { test : true } )
Let me know if it works!
Related
Im trying to create a PrivateRoutes in addition to the regular routes.
After login, the page is successfully re-direct to /home, however when I tried to open /work, the page will go back to /home. all the data from state.valid is also shows "unidentified" in /work.
I figured it out that inside the privateRoutes it check if valid.isAuthenticated is true or not. However since. valid.isAuthenticated is set to false as initial value in reducer, everytime I open /home or /work, it re-render /login and then render /home or /work.
How do I fix to not to render /login before opening other pages?
Here is my PrivateRoutes.js
import React from "react";
import { useSelector } from "react-redux";
import { Navigate } from "react-router-dom";
const PrivateRoute = ({ children }) => {
const valid = useSelector((state) => state.valid);
return valid.isAuthenticated ? children : <Navigate to="/login" />;
};
export default PrivateRoute;
here is my AppRouter.js
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import PrivateRoute from "./PrivateRoute";
import App from "../components/App";
import Login from "../components/Login";
import HomePage from "../components/HomePage";
import WorkPage from "../components/WorkPage";
const AppRouter = () => (
<BrowserRouter>
<div>
<NavigationBar />
<div>
<Routes>
<Route path="/" element={<App />} exact />
<Route path="/login" element={<Login />} exact />
<Route path="/home" element={<PrivateRoute><HomePage /></PrivateRoute>} />
<Route path="/work" element={<PrivateRoute><WorkPage /></PrivateRoute>} />
</Routes>
</div>
</div>
</BrowserRouter>
);
export default AppRouter;
useEffect(() => {
if (valid.isAuthenticated) {
navigate("/home");
}
},[valid.isAuthenticated]);
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import PrivateRoute from "./PrivateRoute";
import App from "../components/App";
import Login from "../components/Login";
import HomePage from "../components/HomePage";
import WorkPage from "../components/WorkPage";
const AppRouter = () => {
useEffect(() => {
if (!valid.isAuthenticated) {
navigate("/login");
}
});
return (
<BrowserRouter>
<div>
<NavigationBar />
<div>
{valid.isAuthenticated ? <>
<Routes>
<Route path="/" element={<App />} exact />
<Route path="/home" element={<HomePage />} />
<Route path="/work" element={<WorkPage />} />
</Routes>
</>
:
<>
<Routes>
<Route path="/login" element={<Login />} exact />
</Routes>
</>
}
</div>
</div>
</BrowserRouter>
)
};
export default AppRouter;
Hi I need help getting my code to work so that when I try to log back in I won't be able to view the dashboard since I logged out. Right now its giving me a blank screen in my project and I think its because privateroute isn't a thing anymore? Not sure. This is my code in PrivateRoute.js:
import React, { Component } from 'react';
import { Route, Navigate } from 'react-router-dom';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
const PrivateRoute = ({ component: Component, auth: { isAuthenticated, loading },
...rest }) => (
<Route {...rest} render={props => !isAuthenticated && !loading ? (<Navigate to='/login' />) : (<Component {...props} />)} />
)
PrivateRoute.propTypes = {
auth: PropTypes.object.isRequired
};
const mapStatetoProps = state => ({
auth: state.auth
});
export default connect(mapStatetoProps)(PrivateRoute);
This is the code for the app.js:
import React, { Fragment, useEffect } from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Navbar from './components/layout/Navbar';
import Landing from './components/layout/Landing';
import Register from './components/auth/Register';
import Login from './components/auth/Login';
import Alert from './components/layout/Alert';
import Dashboard from './components/dashboard/Dashboard';
import PrivateRoute from './components/routing/PrivateRoute';
// Redux
import { Provider } from 'react-redux';
import store from './store';
import { loadUser } from './actions/auth';
import setAuthToken from './utils/setAuthToken';
import './App.css';
if (localStorage.token) {
setAuthToken(localStorage.token);
}
const App = () => {
useEffect(() => {
store.dispatch(loadUser());
}, []);
return (
<Provider store={store}>
<Router>
<Fragment>
<Navbar />
<Routes>
<Route exact path='/' element={<Landing/>} />
</Routes>
<section className="container">
<Alert />
<Routes>
<Route exact path='/Register' element={<Register/>} />
<Route exact path='/Login' element={<Login/>} />
<PrivateRoute exact path='/dashboard' element={Dashboard} />
</Routes>
</section>
</Fragment>
</Router>
</Provider>
)};
export default App;
Please Help!
there is a recommended Protected Route implementation in the v6 react router docs you can follow.
DOCS IMPLEMENTATION
Your issue:
<Route {...rest} render={props => !isAuthenticated && !loading ?
(<Navigate to='/login' />) : (<Component {...props} />)} />
This Route is not up to date with v6, which I assume you are using, you need to update it.
Exact is also not supported anymore, there is no point in including it in your routes.
If you are not using v6 please update your post and include your react-router version.
I am working on a project where I am using the strikingDash template. Here I face some issues of routing while changing the routes from URL.
auth.js
import React, { lazy, Suspense } from "react"
import { Spin } from "antd"
import { Switch, Route, Redirect } from "react-router-dom"
import AuthLayout from "../container/profile/authentication/Index"
const Login = lazy(() =>
import("../container/profile/authentication/overview/SignIn")
)
const SignUp = lazy(() =>
import("../container/profile/authentication/overview/SignUp")
)
const ForgetPassword = lazy(() =>
import("../container/profile/authentication/overview/ForgetPassword")
)
const EmailConfirmation = lazy(() =>
import("../container/profile/authentication/overview/EmailConfirmation")
)
const VerificationPage = lazy(() =>
import("../container/profile/authentication/overview/VerificationPage")
)
const NotFound = () => {
console.log("NOT FOUND")
return <Redirect to="/" />
}
const FrontendRoutes = () => {
return (
<Switch>
<Suspense
fallback={
<div className="spin">
<Spin />
</div>
}
>
<Route exact path="/verification" component={VerificationPage} />
<Route exact path="/email-confirmation" component={EmailConfirmation} />
<Route exact path="/forgetPassword" component={ForgetPassword} />
<Route exact path="/signup" component={SignUp} />
<Route exact path="/" component={Login} />
<Route component={NotFound} />
</Suspense>
</Switch>
)
}
export default AuthLayout(FrontendRoutes)
App.js
import React, { useEffect, useState } from "react";
import { hot } from "react-hot-loader/root";
import { Provider, useSelector } from "react-redux";
import { ThemeProvider } from "styled-components";
import { BrowserRouter as Router, Redirect, Route } from "react-router-dom";
import { ConfigProvider } from "antd";
import store from "./redux/store";
import Admin from "./routes/admin";
import Auth from "./routes/auth";
import "./static/css/style.css";
import config from "./config/config";
import ProtectedRoute from "./components/utilities/protectedRoute";
const { theme } = config;
const ProviderConfig = () => {
const { rtl, isLoggedIn, topMenu, darkMode } = useSelector(state => {
return {
darkMode: state.ChangeLayoutMode.data,
rtl: state.ChangeLayoutMode.rtlData,
topMenu: state.ChangeLayoutMode.topMenu,
isLoggedIn: state.Authentication.login,
};
});
const [path, setPath] = useState(window.location.pathname);
useEffect(() => {
let unmounted = false;
if (!unmounted) {
setPath(window.location.pathname);
}
// eslint-disable-next-line no-return-assign
return () => (unmounted = true);
}, [setPath]);
return (
<ConfigProvider direction={rtl ? "rtl" : "ltr"}>
<ThemeProvider theme={{ ...theme, rtl, topMenu, darkMode }}>
<Router basename={process.env.PUBLIC_URL}>
{!isLoggedIn ? <>{console.log("INSIDE PUBLIC")}<Route path="/" component={Auth} /></> : <ProtectedRoute path="/admin" component={Admin} />}
{isLoggedIn && (path === process.env.PUBLIC_URL || path === `${process.env.PUBLIC_URL}/`) && (
<Redirect to="/admin" />
)}
</Router>
</ThemeProvider>
</ConfigProvider>
);
};
function App() {
return (
<Provider store={store}>
<ProviderConfig />
</Provider>
);
}
export default hot(App);
Whenever I change the URL to another route as I described above in Frontend Routes. Then it will always print console statements like these:
INSIDE PUBLIC
NOT FOUND
INSIDE PUBLIC
NOT FOUND
Expected Behaviour: Whenever I update the URL it will render the component according to the switch case and return it back
Actual Behaviour: Whenever I update the URL it will render the component as well as the default component. I think Switch here renders multiple components, but I don't know why.
I just resolved the issue by moving the Switch Tag inside the Suspense tag in the auth.js file.
The problem should be in the order of your pages: the root path works as a collector of all the pages, you should try to add the exact keyword to the Router path. Here the reference for the differences between the different notations.
<Route exact path="/" component={Login} />
I am trying to change the contents of my Navbar and my Router via useContext and conditional rendering.
This is my App.js:
import "./App.css";
import axios from "axios";
import { AuthContextProvider } from "./context/AuthContext";
import MyRouter from "./MyRouter";
axios.defaults.withCredentials = true;
function App() {
return (
<AuthContextProvider>
<MyRouter />
</AuthContextProvider>
);
}
export default App;
This is my Router:
import React, { useContext } from "react";
import AuthContext from "./context/AuthContext";
import {
BrowserRouter as Router,
Switch,
Route,
Redirect,
} from "react-router-dom";
import MyNavBar from "./components/MyNavbar";
import "./App.css";
import Home from "./components/pages/Home";
import AboutUs from "./components/pages/AboutUs";
import Register from "./components/pages/Register";
import MyFooter from "./components/MyFooter";
import login from "./components/pages/login";
import ProfilePage from "./components/pages/ProfilePage";
function MyRouter() {
const { loggedIn } = useContext(AuthContext);
return (
<Router>
<MyNavBar />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/about-us" component={AboutUs} />
{loggedIn === false && (
<>
<Route exact path="/register" component={Register} />
<Route exact path="/login" component={login} />
</>
)}
{loggedIn === true && (
<>
<Route exact path="/profile" component={ProfilePage} />
</>
)}
<Redirect to="404" />
</Switch>
<MyFooter />
</Router>
);
}
export default MyRouter;
My Navbar's conditional rendering works in the same way as the router. My problem is that neither of the conditional rendering fragments are working. For example, when my application starts, users are not logged in and the "loggedIn" value is false. With this logic, the routes "register" and "login" should be accessible, but they are not. Any advice or help would be greatly appreciated as I am quite new to using React.
Here is a screenshot of my console upon loading the application
This is my "AuthContext":
const AuthContext = createContext();
function AuthContextProvider(props) {
const [loggedIn, setLoggedIn] = useState(undefined);
async function getLoggedIn() {
const loggedInRes = await axios.get(
"http://localhost:5000/api/users/loggedIn"
);
setLoggedIn(loggedInRes.data);
}
useEffect(() => {
getLoggedIn();
}, []);
return (
<AuthContext.Provider value={{ loggedIn, getLoggedIn }}>
{props.children}
</AuthContext.Provider>
);
}
export default AuthContext;
export { AuthContextProvider };
Thanks for all the help guys, I learned a lot about the ProtectedRoute concept. My issue came from my Navigation Bar component. Instead of declaring my variable as an object, I declared loggedin like
const loggedIn = useContext(AuthContext);
All my errors were solved once I changed it to
const { loggedIn } = useContext(AuthContext);
Edited:
Instead of using your conditions in your main route, you can create a ProtectedRoute which Routes your component according to your condition.
import React, { useEffect } from "react";
import { Route, Redirect, useHistory } from "react-router-dom";
const ProtectedRoute = ({ component: Component, ...rest }) => {
const { loggedIn } = useContext(AuthContext);
return (
<Route
{...rest}
render={(props) =>
loggedIn() ? (
<Component {...props} />
) : (
<Redirect to='/login' />
)
}
/>
);
};
export default ProtectedRoute;
In your component you can change your logic with this:
<ProtectedRoute exact path="/" component={Home} />
<ProtectedRoute exact path="/about-us" component={AboutUs}/>
<Route exact path="/register" component={Register} />
<Route exact path="/login" component={login} />
<ProtectedRoute exact path="/profile" component={ProfilePage} />
This means that if you wanna protect a route you should route it with ProtectedRoute otherwise classic react route.
You can read about that ProtectedRoute concept here
I want to make a dynamic url for /:user that does not run in certain urls. Since /:user is linked to base, it runs for every route I made. Is there a way to exclude specific url routes? I purposely DO NOT want to make url handles like /user/:userid to fix this issue.
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route } from "react-router-dom";
import { createBrowserHistory } from "history";
import { AuthProvider } from '../src/components/provider/AuthProvider.js';
import Register from '../src/views/Register';
import Login from '../src/views/Login';
import Admin from '../src/views/Admin';
import User from '../src/views/User';
import App from './App';
import './assets/scss/style.scss';
const history = createBrowserHistory();
ReactDOM.render(
<AuthProvider>
<Router history={history}>
<App />
<Route path="/register" component={Register} />
<Route path="/login" component={Login} />
<Route path="/admin" component={Admin} />
<Route path="/:user" component={User} />
</Router>
</AuthProvider>,
document.getElementById('root')
);
const User = ({ match, location }) => {
let load = true;
if (location.pathname === '/admin' || location.pathname === '/login' || location.pathname === '/register') {
load = false;
}
return (
<React.Fragment>
{load &&
<h1>this is user {match.params.user}'s page</h1>
}
</React.Fragment>
)
}
export default User;
You can make a Private route component in which you can pass a method which makes sure you are authenticated.
isAuthenticate Method
export const isAuthenticated = () => {
if(typeof window === undefined){
return false;
}
if(localStorage.getItem("jwt")){
return JSON.parse(localStorage.getItem("jwt"));
}else{
return false;
}
}
PrivateRoute.js
const PrivateRoute = ({component:Component, ...rest}) => {
return <Route
{...rest}
render={props=>
isAuthenticated()?(<Component {...props}/>
):(
<Redirect
to={{
pathname:"/login",
state:{ from:props.location }
}}
/>
)}
/>
}