I want to do a type of authorization in react, but I ran into a problem when I add a token in one component, the 2nd does not see it, but sees it only after reloading the application.
How can this be corrected in the react?
import React from 'react';
import {NavLink} from "react-router-dom";
const Login = () => {
const handleLogin = () => {
console.log( localStorage.getItem('token'));
localStorage.setItem('token', 'token');
}
return (
<div>
<header className="">
<ul>
<li><NavLink to="/main" activeClassName={'active-link'}>Home</NavLink></li>
</ul>
</header>
<button onClick={handleLogin}>login</button>
</div>
);
};
export default Login;
App.js
import './App.css';
import React from 'react';
import {Route,Redirect,Switch} from 'react-router-dom'
import Login from "./pages/login";
import Logout from "./pages/logout";
import Main from "./pages/main";
import ErrorPage from "./pages/error";
function App() {
return (
<div className="App">
<div>ore</div>
<Switch>
<Route exact path="/">
<Redirect to="/login" />
</Route>
{
localStorage.getItem('token') ? <Route path="/main" component={Main} /> : null
}
<Route path="/login" component={Login} />
<Route path="/portfolio" component={Logout} />
<Route path="/error" exact component={ErrorPage} />
<Redirect to={'/error'} />
</Switch>
</div>
);
}
export default App;
you can use the useEffect and useState into your app.js
const [token, setToken] = useState([]);
const tokenFromLogin = localStorage.getItem("token");
useEffect(() => {
setToken(tokenFromLogin);
}, [jwt]);
Related
I am building a MERN stack app and I am trying to check if the user is actually an admin. I am using the same database for two front end apps, one is a dashboard in which I have this problem and I can only check if the user is logged in but not if he is an admin.
import CssBaseline from "#mui/material/CssBaseline";
import { ThemeProvider } from "#mui/material/styles";
import { createTheme } from "#mui/material";
import { useEffect, useMemo, useState } from "react";
import { useSelector } from "react-redux";
import { themeSettings } from "theme";
import { Routes, Route, Navigate } from "react-router-dom";
import Dashboard from "scenes/dashboard";
import Layout from "scenes/layout";
import NewProduct from "scenes/newProduct/NewProduct";
import Products from "scenes/products/Products";
import SingleProduct from "scenes/singleProduct/SingleProduct";
import Login from "scenes/login/Login";
import Users from "scenes/utilisateurs/users";
function App() {
const mode = useSelector((state) => state.global.mode);
const theme = useMemo(() => createTheme(themeSettings(mode)), [mode]);
const userLogin = useSelector((state) => state.userLogin)
const { userInfo } = userLogin
return (
<div className="app">
<ThemeProvider theme={theme}>
<CssBaseline />
<Routes>
<Route path="/login" element={<Login />} />
<Route
element={userInfo ? <Layout /> : <Navigate to="/login"/>}
>
<Route path="/" element={<Dashboard />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/newproduct" element={<NewProduct />} />
<Route path="/products" element={<Products />} />
<Route path="/products/:id" element={<SingleProduct />} />
<Route path="/utilisateurs" element={<Users />} />
</Route>
</Routes>
</ThemeProvider>
</div>
);
}
export default App;
so with this first code it only checked for the userinfo but when I add userInfo.isAdmin
<Route element={userInfo.isAdmin ? <Layout /> : <Navigate to="/login"/>} >
I get this error
App.js:32 Uncaught TypeError: Cannot read properties of null (reading 'isAdmin')
Although I am sure that the useInfo does have the isAdmin value in redux state and also in the localStorage.
What Im I doing wrong here?
I'm using framer-motion with react to make transitions between my pages, but I have an issue with one transition.
When I'm in the homepage, scroll a bit and click on the menu to go to other page, the next page is empty. In fact by looking in the inspector I can see that the previous page (home) is still in the DOM (+ the new one) and did not exit.
video of the bug : https://www.awesomescreenshot.com/video/11523168
Here's my home component :
import React, {useState, useEffect, useContext} from 'react'
import FirstSection from './FirstSection/FirstSection';
import StickyNav from './FirstSection/StickyNav/StickyNav';
import SndSection from "../sections/Content2/SndSection.js"
import './Home.css';
import LeftOne from "../sections/FirstSection/LeftOne.js";
import ThirdSection from './Content3/ThirdSection';
import { slideContext } from '../../App';
import { motion } from 'framer-motion';
export default function Home() {
const context = useContext(slideContext);
const [scroll, setScroll] = useState();
useEffect(() => {
const handleScroll = event => {
setScroll(window.scrollY);
};
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
return (
<motion.div
id={context.end ? "end-transition" : ""}
className='home'
initial={{width:0, opacity:0}}
animate={{width:'100%', opacity:1}}
exit={{x:window.innerWidth, transition:{duration: 0.3}, opacity:0}}
>
{scroll >= 100 ? <StickyNav /> : ""}
<div id="page">
<LeftOne element='v1'/>
<div id="ctn">
<FirstSection />
<SndSection />
<ThirdSection />
</div>
</div>
</motion.div>
)
}
App.js :
return (
<HashRouter>
<slideContext.Provider value={{end, setEnd, endInscr, setEndInscr, number, setNumber}}>
<div className="App">
<AnimatedRoutes />
</div>
</slideContext.Provider>
</HashRouter>
);
AnimatedRoutes :
import React from 'react'
import {Routes, Route, useLocation} from "react-router-dom";
import AboutUs from './AboutUs/AboutUs';
import Error from './Error';
import Inscription from './Inscription/Inscription';
import Thanks from './Inscription/Thanks';
import Privacy from './Privacy/Privacy';
import Home from './sections/Home';
import Terms from './Terms&Conditions/Terms';
import {AnimatePresence} from 'framer-motion';
export default function AnimatedRoutes() {
const location = useLocation();
return (
<AnimatePresence>
<Routes location={location} key={location.pathname}>
<Route path='/' element={<Home />} />
<Route path='/register' element = {<Inscription />} />
<Route path='/thanks-registration' element ={<Thanks />} />
<Route path='/aboutUs' element={<AboutUs />}/>
<Route path='/termsAndConditions' element={<Terms />} />
<Route path="/privacy" element={<Privacy />}/>
<Route path="/error" element={<Error />} />
</Routes>
</AnimatePresence>
)
}
My render page
import "./splash.css";
import { Redirect } from 'react-router-dom';
import React from 'react';
function Splash() {
const login = () => {
console.log('123')
return <Redirect to='/login' />;
}
const signup = () => {
return <Redirect to='/sign-up' />;
}
return (
<>
<div className="bannerContainer">
<h1>Costco Connect</h1>
</div>
<div className="formContainer">
<div
className="loginContainer"
onClick={login}
>
<h2>Login</h2>
</div>
<div
className="loginContainer"
onClick={signup}
>
<h2>Sign Up</h2>
</div>
</div>
</>
);
}
export default Splash;
And my app.js
import React, { useState, useEffect } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import SignUpForm from './components/auth/SignUpForm';
import NavBar from './components/NavBar';
import ProtectedRoute from './components/auth/ProtectedRoute';
import UsersList from './components/UsersList';
import User from './components/User';
import { authenticate } from './store/session';
import Tickets from './components/Tickets';
import Departments from './components/Departments';
import Splash from './components/Splash';
import LoginForm from './components/auth/LoginForm';
function App() {
const [loaded, setLoaded] = useState(false);
const dispatch = useDispatch();
useEffect(() => {
(async () => {
await dispatch(authenticate());
setLoaded(true);
})();
}, [dispatch]);
if (!loaded) {
return null;
}
return (
<BrowserRouter>
<ProtectedRoute >
<NavBar />
</ProtectedRoute>
<Switch>
<Route path='/login' exact={true}>
<LoginForm />
</Route>
<Route path='/sign-up' exact={true}>
<SignUpForm />
</Route>
<ProtectedRoute path='/users' exact={true} >
<UsersList />
</ProtectedRoute>
<ProtectedRoute path='/users/:userId' exact={true} >
<User />
</ProtectedRoute>
<Route path='/' exact={true} >
<Splash />
</Route>
<ProtectedRoute path='/departments' exact={true} >
<Departments />
</ProtectedRoute>
<ProtectedRoute path='/departments/:departmentId/tickets' exact={true} >
<Tickets />
</ProtectedRoute>
{/*
<ProtectedRoute path='/departments/:departmentId/tickets/:ticketId' exact={true} >
<Tickets />
</ProtectedRoute> */}
</Switch>
</BrowserRouter>
);
}
export default App;
Basically I'm trying to make it when you click on a div it will send you to the relevant form to either sign up or log in but I cannot figure out why the url isn't being redirected. If I throw a console.log inside of the functions they are running so I'm convinced the bug is in my app.js somewhere but I've run out of things to try. Thanks in advance, I've looked at other similar posts but no solutions have helped so far.
The solution was to use a NavLink instead, the Redirects were only working if they were inside a conditional and then returning.
hi hope someone can help me. I have added pagination into my react app. I have checked and the query strings are working as they should be on the back end. However when I try and click through the pagination buttons it adds extra to the URL so instead of localhost:3000/topic/page/1 it is localhost:3000/topic/page/topic/page/1. Therefore I get a not found error when I click on the link.
Routes file
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import Register from '../auth/Register';
import Login from '../auth/Login';
import Alert from '../layout/Alert';
import Dashboard from '../dashboard/Dashboard';
import CreateProfile from '../profile-forms/CreateProfile';
import EditProfile from '../profile-forms/EditProfile';
import Profiles from '../profiles/Profiles';
import Profile from '../profile/Profile';
import Posts from '../posts/Posts';
import Post from '../post/Post';
import Topics from '../topic/Topics';
import Flashcard from '../flashcard/Flashcard';
import Quiz from '../quiz/Quiz';
import Factsheet from '../factsheet/Factsheet';
import NotFound from '../layout/NotFound';
import PrivateRoute from '../routing/PrivateRoute';
const Routes = () => {
return (
<section className="container">
<Alert />
<Switch>
<Route exact path="/register" component={Register} />
<Route exact path="/login" component={Login} />
<PrivateRoute exact path="/profiles" component={Profiles} />
<PrivateRoute exact path="/profile/:id" component={Profile} />
<PrivateRoute exact path="/dashboard" component={Dashboard} />
<PrivateRoute exact path='/create-profile' component={CreateProfile} />
<PrivateRoute exact path='/edit-profile' component={EditProfile} />
<PrivateRoute exact path='/topic' component={Topics} />
<PrivateRoute exact path='/topic/search/:keyword' component={Topics} />
<PrivateRoute exact path='/topic/page/:pageNumber' component={Topics} />
<PrivateRoute exact path='/topic/search/:keyword/page/:pageNumber' component={Topics} />
<PrivateRoute exact path='/topic/flashcard/:id' component={Flashcard} />
<PrivateRoute exact path='/topic/quiz/:id' component={Quiz} />
<PrivateRoute exact path='/topic/factsheet/:id' component={Factsheet} />
<PrivateRoute exact path="/posts" component={Posts} />
<PrivateRoute exact path="/posts/:id" component={Post} />
<Route component={NotFound} />
</Switch>
</section>
);
};
export default Routes;
Paginate.js
import React from 'react'
import { Pagination } from 'react-bootstrap'
import { Link } from 'react-router-dom';
import { LinkContainer } from 'react-router-bootstrap'
const Paginate = ({ pages, page, keyword = '' }) => {
return (
pages > 1 && (
<Pagination>
{[...Array(pages).keys()].map((x) => (
<LinkContainer
tag={Link}
key={x + 1}
to={keyword
? `topic/search/${keyword}/page/${x + 1}`
: `topic/page/${x + 1}`
}
>
<Pagination.Item active={x + 1 === page}>{x + 1}</Pagination.Item>
</LinkContainer>
))}
</Pagination>
)
)
}
export default Paginate
SearchBox.js
import React, { useState } from 'react'
import { Form, Button } from 'react-bootstrap'
const SearchBox = ({ history }) => {
const [keyword, setKeyword] = useState('')
const submitHandler = (e) => {
e.preventDefault()
if(keyword.trim()) {
history.push(`/topic/search/${keyword}`)
} else {
history.push('/topic')
}
}
return (
<Form onSubmit={submitHandler} inline>
<Form.Control
type="text"
name="q"
onChange={(e) => setKeyword(e.target.value)}
placeholder="Search Topics....."
></Form.Control>
</Form>
)
}
export default SearchBox
topic.js
import React, { Fragment, useEffect } from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Spinner from '../layout/Spinner';
import Paginate from '../layout/Paginate'
import TopicItem from './TopicItem';
import { getTopics } from '../../actions/topic';
const Topics = ({ getTopics, topic: { topics, loading, pages, page }, match }) => {
const keyword = match.params.keyword
const pageNumber = match.params.pageNumber || 1
useEffect(() => {
getTopics(keyword, pageNumber);
}, [getTopics, keyword, pageNumber])
return (
<Fragment>
{loading ? (
<Spinner />
) : (
<Fragment>
<h1 className="large text-primary1 my-2">Pick a Topic</h1>
<Link to="/topic" className="btn my-4">
Back To Topics
</Link>
<div className="card-grid-home">
{topics.length > 0 ? (
topics.map(topic => (
<TopicItem key={topic._id} topic={topic} />
))
) : (
<h4>No topics found......</h4>
)}
</div>
<Paginate pages={pages} page={page} keyword={keyword ? keyword : ''}/>
</Fragment>
)}
</Fragment>
)
};
Topics.prototype = {
getTopics: PropTypes.func.isRequired,
topic: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
topic: state.topic
})
export default connect(mapStateToProps, { getTopics })(Topics)
Thanks in advance
Realised that I was missing a / for the start of the routes. Silly mistake.
I am attempting to redirect from the root url of my app and I get the above error. I have read some of the other answers here on SO that reference this error but they center on state being updated cyclically and I can't see where I'm doing it in the Router:
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter as Router, Route, Switch, Redirect} from 'react-router-dom'
import BookDetails from './BookDetails'
import NavBar from './NavBar'
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<>
<Router>
<NavBar/>
<Switch>
<Redirect from="/" to="/search" component={App} /> {/** */}
<Route path="/search" component={App} />
<Route path="/" component={App} />
</Switch>
<Route path="/book/:bookId" component={BookDetails} />
</Router>
</>
, document.getElementById('root'));
Or in the App.js file which I hope is okay :
import React, {useState, useEffect} from 'react'
import {Link} from 'react-router-dom'
// import debounce from 'lodash'
import noimage from './noimage.png'
import axios from 'axios'
import './App.css';
const App = (props) =>{
const [books,setBooks] = useState([])
const [isLoading,setIsLoading] = useState(false)
const [hasError,setHasError] = useState(false)
const [searchTerm,setSearchTerm] = useState('')
console.log("props",(props.history.location.pathname))
const input = str => {
console.log(str)
setSearchTerm(str)
getData(str)
}
const getData = async () => {
if(searchTerm && searchTerm.length >= 2){
if(isLoading === false)setIsLoading(true)
let s = `http://localhost:7000/books/search/${searchTerm}`
await axios.get(s)
.then(resp => {
console.log(resp.data.books)
if(books === [])setBooks([...resp.data.books])
//props.history.push(s)
})
.catch(error => {
console.log(error)
setHasError(true)
setIsLoading(false)
})
}
if(isLoading === true) setIsLoading(false)
}
const img = {
height : "175px",
width : "175px"
}
// useEffect(() =>{
// setTimeout(() => getData(),2250)
// },[])
return isLoading ? (
<div className="App">
<div className="spinner"></div>
<div className="App loading">
<p><i>loading...</i></p>
</div>
</div>
)
: hasError ? (
<div className="App loading-error">
⚠ There is a network issue: Please try again later
</div>
)
:
(
<div className="App">
<div className="search">
<div className="container">
<div className="content">
<input
type="search"
placeholder="Search..."
aria-label="Search"
className="search-form"
value={searchTerm}
onChange={e => input(e.target.value)}
/>
</div>
</div>
</div>
{
(books && books.length >= 1) &&
books.map((b,i) => {
console.log(typeof b.imageLinks)
return (
<div key={`${b.title}-${i}`} className="search-book">
<Link to={`/book/${b.id}`}>
{
(b.imageLinks === undefined || b === undefined || b.imageLinks.thumbnail === undefined) ?
<img src={noimage} alt ="Missing" style={img}></img>
:
<img src={b.imageLinks.thumbnail} alt={b.title}></img>
}
</Link>
<p>{b.title}</p>
<hr/>
</div>
)}
)
}
</div>
)
}
export default App;
I can't demo the code since it involves a REST Api server that's local to my machine. Thanks.
Well my instructor suggested this : https://reacttraining.com/react-router/web/api/Switch
and I thought I tried this already but I read the docs and tried this -
(
<Router>
<NavBar/>
<Switch>
<Redirect exact from="/" to="/search" component={App} />
<Route path="/search" component={App} />
<Route path="/book/:bookId" component={BookDetails} />
</Switch>
</Router>
)
The exact property isn't needed on all the routes. But I thank Kishan for his effort, he definitely was on the right track. Thanks again.
<>
<Router>
<NavBar/>
<Switch>
<Redirect from="/" to="/search" component={App} /> {/** */}
<Route exact path="/search" component={App} />
<Route exact path="/book/:bookId" component={BookDetails} />
</Switch>
</Router>
</>
try this way, maybe helps you