problems on page refresh - javascript

I have built an admin panel using react. After logging in to the panel whenever the user refreshes the page, everything disappears, I don't know why its happening.
Its working fine without the signin page but after adding the signin page it doesn't.
Here is the App.js file code where all the Routes are defined.
import React, { useState } from "react";
import { Route, Switch } from "react-router-dom";
import { Link } from "react-router-dom";
import * as FaIcons from "react-icons/fa";
import SideMenu from "./SideMenu";
import Dashboard from "./components/Dashboard";
import Registration_Request from "./components/Registration_Request";
import Users from "./components/Users";
import Seller from "./components/Request Pages/Seller";
import Reseller from "./components/Request Pages/Reseller";
import Sales from "./components/Request Pages/Sales";
import Sellers from "./components/Sellers";
import Character_Upload from "./components/Character_Upload";
import Campaign_Design from "./components/Campaign_Design";
import Levels_Design from "./components/Levels_Design";
import SellingCoins from "./components/SellingCoins";
import SignIn from "./SignIn";
function App() {
let [signedIn, isSignedIn] = useState(false);
return (
<>
<div className="header"></div>
<div className="main-content">
<Switch>
<Route path="/" exact>
<SignIn signedIn={signedIn} isSignedIn={isSignedIn} />
</Route>
{signedIn && (
<>
<SideMenu />
<Route path="/dashboard" exact component={Dashboard} />
<Route path="/registration-request/seller" component={Seller} />
<Route
path="/registration-request/reseller"
component={Reseller}
/>
<Route path="/registration-request/sales" component={Sales} />
<Route path="/users" component={Users} />
<Route path="/sellers" component={Sellers} />
<Route path="/character-upload" component={Character_Upload} />
<Route path="/campaign-design" component={Campaign_Design} />
<Route path="/levels-design" component={Levels_Design} />
<Route path="/sellingcoins" component={SellingCoins} />
</>
)}
</Switch>
</div>
</>
);
}
export default App;

The signedIn state only lives in memory, and the initial value is false. When you reload the page, you reload the app, which remounts/reinitializes the components.
The solution is typically to persist your app state to local storage, and initialize from localStorage.
Using a state lazy initializer function you can read the localStorage for the saved state and set the initial state.
const [signedIn, isSignedIn] = useState(() => {
return !!JSON.parse(localStorage.getItem("signedIn"));
});
Use an useEffect hook to persist state changes to localStorage. When a user signs in and the signedIn state updates, this will trigger the useEffect hook's callback and will save the state value into localStorage.
useEffect(() => {
localStorage.setItem("signedIn", JSON.stringify(signedIn));
}, [signedIn]);

The signedIn flag will be set to false on page refresh. Instead of using it in the state variable use the local Storage/ Session Storage.
you can read more about local storge

Related

How to solve "Functions are not valid as a React child." error when I try to render a components based on the output of a function?

In my App.js file of the application, I am setting the routes of the app.
This is the code of my App.js file
import React, {useEffect} from "react";
import {Container} from '#material-ui/core';
import {BrowserRouter, Routes, Route, Navigate} from 'react-router-dom';
import { gapi } from 'gapi-script';
import Navbar from "./components/Navbar/Navbar";
import Home from './components/Home/Home';
import Auth from "./components/Auth/Auth";
import MealsPage from "./components/MealsPage/MealsPage";
import WorkoutDetails from "./components/WorkoutDetails/WorkoutDetails";
const App=()=>{
const user=JSON.parse(localStorage.getItem('profile'));
useEffect(() => {
const start = () => {
gapi.auth2.init({
clientId: process.env.REACT_APP_GOOGLE_API_TOKEN,
scope: ""
})
};
gapi.load('client:auth2', start);
})
return(
<BrowserRouter>
<Container maxWidth="xl">
<Navbar/>
<Routes>
<Route path="/" exact ={()=>{<Navigate to="/workouts"/>}}/>
<Route path="/workouts" exact element={<Home/>}/>
<Route path="/workouts/search" exact element={<Home/>}/>
<Route path="/workouts/:id" element={<WorkoutDetails/>}/>
<Route path="/meals" exact element={<MealsPage/>}/>
<Route path="/auth" exact element={()=>{!user? <Auth/>:<Navigate to="/workouts"/>}}/>
</Routes>
</Container>
</BrowserRouter>
);
}
export default App;
I am getting an error that says this:
react-dom.development.js:67
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.
I assume it is from the Auth route as it does not specify an element to render when we have that specific route, but it specifies a function. Basically, when the user is logged in, he should not see the auth component because he is already logged in and he should be redirected to the '/workouts' route which is another page in the application.
Could you help me solve this?
Here
element={()=>{!user? <Auth/>:<Navigate to="/workouts"/>}}.
Try it like element={user? <Navigate to="/workouts"/> : <Auth/>} or return component like element={()=>!user? <Auth/>:<Navigate to="/workouts"/>} or
element={()=>{return !user? <Auth/>:<Navigate to="/workouts"/>}}
Looking at the documentation for <Route />, the element prop is meant to be an element - not a function returning an element.
Therefore, you should simply be able to remove the function call and pass the element directly:
<Route
path="/auth"
exact
element={!user ? <Auth/> : <Navigate to="/workouts"/>}
/>

React router dom navigate method is not working properly

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>
</>
);
}

React js: React router not redirecting when button is being clicked

I have been trying to solve this problem for couple days and still couldnt get it to work. How does redirecting not work here? I keep getting the "TypeError: history is undefined". Also when the button is being clicked, it stays at the same url. What am I doing wrong?
import React from 'react';
import Nav from './Nav';
import About from './About';
import Service from './Service';
import Home from './Home';
import {
BrowserRouter as Router,
Switch,
Route,
useHistory,
} from 'react-router-dom';
function App() {
const history = useHistory();
function handleSub() {
// console.log('clicked');
history.push('/about');
}
return (
<div className='App'>
<button onClick={handleSub}>submit</button>
<Router>
<Nav />
<Switch>
<Route path='/' exact component={Home} />
<Route path='/about' component={About} />
<Route path='/service' component={Service} />
</Switch>
</Router>
</div>
);
}
export default App;
Edit: implemented the answers and still having trouble.
Suggestion 1: place the button inside the router: url switches for links or button is clicked but pages for the links not when the button is clicked.
function App() {
const history = useHistory();
function handleSub() {
// console.log('clicked');
history.push(`/about`);
}
return (
<Router>
<div className='App'>
<Nav />
<button onClick={handleSub}>submit</button>
<Switch>
<Route path='/' exact component={Home} />
<Route path='/about' component={About} />
<Route path='/service' component={Service} />
</Switch>
</div>
</Router>
);
}
Suggestion number two: url swtich for all the links and button but the page never loads.
function App() {
const history = useHistory();
function handleSub() {
// console.log('clicked');
history.push(`/about`);
}
return (
<Router>
<div className='App'>
<Nav />
<Switch>
<button onClick={handleSub}>submit</button>
<Route path='/' exact component={Home} />
<Route path='/about' component={About} />
<Route path='/service' component={Service} />
</Switch>
</div>
</Router>
);
}
Simply because you are calling useHistory hook outside of React Router Switch Component, meaning you should use this hook in all Switch child components, otherwise the history object is undefined. The best way for my opinion is to move the button to the Home Component, then surly it will work.
I hope this answer helped you.
If you use it like this
<Button color='primary' onClick={handleSub('/about')}>Submit</Button>
and in your method do it like this.
const handleSub = (path) => async (e) => {
history.push(path)}
I hope it will solve your issue.
It's not the placement of the button which is the issue, but as originally mentioned, the placement of useHistory. The history hook is expecting context provided by the Router component - if you are familiar with useContext, it's exactly the same here. You must be calling useHistory inside a component which is a child of Router.
I'll mock an index.js file to demonstrate:
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import App from './App';
const rootHtml = (
<Router>
<App />
</Router>
);
ReactDOM.render(rootHtml, document.getElementById('root'));
Remove the original router in the App component. Now this top level router has the App component in scope and can provide it with history context for useHistory to use.

React router history push always route to 404 page

js and facing hard time with react router dom.
I want to change the route when I click a button in my navigation drawer component.
This is my App.js component.
import { Router, Route, Switch } from "react-router-dom";
function App() {
const classes = useStyles();
return (
<Provider store={store}>
<div className={classes.root}>
<NavBar />
<Drawer />
<Router history={history}>
<Switch>
<Route path="/" exact component={Login}></Route>
<Route path="/country" exact component={Country}></Route>
<Route path="/user-create" exact component={User}></Route>
<Route path="/countries" exact component={ListView}></Route>
<Route component={NotFound}></Route>
</Switch>
</Router>
</div>
</Provider>
);
}
And here I pass history prop to the Router component.
History.js
import { createBrowserHistory } from 'history';
export default createBrowserHistory();
Drawer.js
import history from '../../history'
const onRoute = (path) => {
history.push("/user-create");
// props.toggleDrawer();
}
In Drawer.js it is always route to the NotFoundComponet.
Why could this happen?
In your NavBar and Drawer components include the below withRouter or the alt useHistory hook to get access to the history prop.
import { withRouter } from 'react-router'
...
this.props.history.push('/user-create')
...
export default withRouter(...
I'd put <NavBar /> and <Drawer /> inside <Router>, and do
const { push } = useHistory() // from react-router-dom
inside them, to get a reference of the push API

Integrating react-cookie with react redux

My main application is based on this old boilerplate which I have been slowly updating. Currently, all of the dependencies have been updated except for react-cookie.
I am trying to upgrade react-cookie to version 3.0.4 using this tutorial but I need some help overcoming some challenges I am facing during the transition process.
Following the tutorial, I changed index.js to
ReactDOM.render(
<CookiesProvider>
<Provider store={store}>
<App />
</Provider>
</CookiesProvider>,
document.querySelector('.wrapper'));
Now, my app.js file looks like this:
import React, { Component } from 'react'
import { withCookies } from 'react-cookie'
import Routes from '../Routes'
class App extends Component {
render() {
return (
<div className="container">
<Routes cookies={this.props.cookies} />
</div>
);
}
}
export default withCookies(App)
Now, my biggest concern comes here. My Routes component was never meant to be a Redux container so I changed it to this to accommodate the tutorial:
import React from 'react'
import { connect } from 'react-redux'
import { BrowserRouter, Route, Switch } from 'react-router-dom'
import ScrollUpButton from 'react-scroll-up-button'
// Import miscellaneous routes and other requirements
import NotFoundPage from './components/pages/not-found-page'
// Import Header and footer
import HeaderTemplate from './components/template/header'
import FooterTemplate from './components/template/footer'
// Import static pages
import HomePage from './components/pages/home-page'
// Import authentication related pages
import Register from './components/auth/register'
import Login from './components/auth/login'
import Logout from './components/auth/logout'
import ForgotPassword from './components/auth/forgot_password'
import ResetPassword from './components/auth/reset_password'
import ConfirmationMessage from './components/auth/confirmation_message'
import ResendVerificationEmail from './components/auth/resend_verification_email'
// Import dashboard pages
import Dashboard from './components/dashboard/dashboard'
import ChangePassword from './components/dashboard/profile/change-password'
// Import simulator pages
import Simulator from './components/simulator/index'
// Import higher order components
import RequireAuth from './components/auth/require_auth'
const BrowserRoutes = () => (
<BrowserRouter>
<div>
<HeaderTemplate logo="Stress Path Simulator" />
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/register" component={Register} />
<Route exact path="/login" component={Login} />
<Route exact path="/logout" component={Logout} />
<Route exact path="/forgot-password" component={ForgotPassword} />
<Route exact path="/reset-password/:resetToken" component={ResetPassword} />
<Route exact path="/confirmation-message" render={() => <ConfirmationMessage message="Please click on the link we sent to your email to verify your account." /> } />
<Route exact path="/resend-verification-email" component={ResendVerificationEmail} />
<Route exact path="/profile/change-password" component={RequireAuth(ChangePassword)} />
<Route exact path="/confirmation-password-changed" render={() => RequireAuth(<ConfirmationMessage message="Password has been successfully changed!" />)} />
<Route exact path="/simulator" component={RequireAuth(Simulator)} />
<Route exact path="/dashboard" component={RequireAuth(Dashboard)} />
<Route component={NotFoundPage} />
</Switch>
<FooterTemplate />
<ScrollUpButton />
</div>
</BrowserRouter>
);
const mapStateToProps = (state, ownProps) => {
return ({
state: state,
cookies: ownProps.cookies
});
}
export const Routes = connect(mapStateToProps, null)(BrowserRoutes)
export default Routes
I believe the problem essentially arises here. By doing so, I thought I would have been able to use the cookies from every single component like this:
//get this.props.cookies
const { cookies } = this.props;
//setting a cookie
cookies.set('name', 'Ross', { path: '/' });
//getting a cookie
cookies.get('name');
However, that doesn't seem the case and I cannot get cookies to work in any of my components especially in my actions/auth.js.
Does anyone have any suggestions? How can I efficiently use cookies in this scenario? I am assuming I can send down the cookies prop to each component that needs it but I am curious to find out what could be the best/cleanest way of using react-cookie with redux. I am fairly new to the MERN JavaScript software stack and mostly self-thought so I am a bit confused about some concepts. For example, if in Routes I am saving cookies into the redux's store, how can I access those cookies afterwards?
Instead of passing the cookies from the App/Router down, it is better to wrap only the components that will need the cookies. For example your Login component would look like this:
class Login extends React.Component {
render() {
let { cookies } = this.props;
let useCookie = cookies.get("testCookie");
...
}
}
export default withCookies(connect(mapStateToProps, null)(Login));

Categories

Resources