AuthStateChange React - javascript

I'm trying see if there is a user with firebase but every time I login into my app and console.log the user it says that there is no user and I can't log into my app.
import React,{Component} from 'react';
import SignUp from './components/Authentication/SignUp';
import {BrowserRouter as Router,Switch,Route,Link} from 'react-router-dom';
import Feed from './components/Feed/Feed';
import Search from './components/SearchUser/Search';
import Profile from './components/Profile/Profile';
import Header from './components/Header/Header';
import firebase from './util/firebase';
class App extends Component
{
constructor(){
super();
this.state={
user:''
}
}
componentDidMount(){
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
this.setState({
user:user
})
// ...
} else {
// User is signed out.
// ...
}
});
}
render(){
const {user}=this.state;
console.log(user);
return(
<div>
{
user?(
<Router>
<Header/>
<Switch>
<Route exact path="/feed">
<Feed user={user}/>
</Route>
<Route path="/search">
<Search/>
</Route>
<Route path="/profile">
<Profile/>
</Route>
</Switch>
</Router>
):(
<SignUp/>
)
}
</div>
)
}
}
export default App;

Problem: there is no user because react is rendering the component before onAuthStateChanged's changes in your state so when it renders user is null.
Solution: (Probably not the best approach):
show the fall back UI while it's updating the State.
I'm sharing my solution by changing your code.
It worked for me when I faced the same issue.
import React,{Component} from 'react';
import SignUp from './components/Authentication/SignUp';
import {BrowserRouter as Router,Switch,Route,Link} from 'react-router-dom';
import Feed from './components/Feed/Feed';
import Search from './components/SearchUser/Search';
import Profile from './components/Profile/Profile';
import Header from './components/Header/Header';
import firebase from './util/firebase';
class App extends Component
{
constructor(){
super();
this.state={
user:'',
loading: true
}
}
componentDidMount(){
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
this.setState({
user:user,
loading: false
})
// ...
} else {
// User is signed out.
// ...
}
});
}
render(){
const {user, loading}=this.state;
console.log(user);
if(loading) return <div>loading...</div>
return(
<div>
{
user?(
<Router>
<Header/>
<Switch>
<Route exact path="/feed">
<Feed user={user}/>
</Route>
<Route path="/search">
<Search/>
</Route>
<Route path="/profile">
<Profile/>
</Route>
</Switch>
</Router>
):(
<SignUp/>
)
}
</div>
)
}
}

Related

Invalid login-check system with a custom hook

AuthRoute.jsx
import React from 'react';
import { useAuth } from 'react-firebase-hooks/auth';
import { Route, Redirect } from 'react-router-dom';
function AuthRoute({ children, ...rest }) {
const { user } = useAuth();
return (
<Route
{...rest}
render={({ location }) =>
user ? (
children
) : (
<Redirect
to={{
pathname: '/login',
state: { from: location }
}}
/>
)
}
/>
);
}
export default AuthRoute;
App.jsx
import { auth } from "./components/base";
import { useAuthState } from "react-firebase-hooks/auth";
import React from "react";
import Home from "./pages/Home";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Login from "./pages/Login";
import Register from "./pages/Register";
import MainPage from "./pages/MainPage";
import AuthRoute from "./pages/AuthRoute";
function App() {
const [user, loading] = useAuthState(auth);
return (
<div>
<Router>
<Routes>
<Route path="/" element={<Home />} />
<AuthRoute path="/mainpage" exact element={MainPage} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
</Routes>
</Router>
</div>
);
}
export default App;
The point is:
I created a custom hook AuthRoute.jsx which checks if the user is logged in via useAuth.
When a user tries to proceed to MainPage.jsx and if he's not logged in (Login.jsx) (I also connected my application to Firebase Auth so the information should be there), he can't proceed to MainPage.jsx.
However, if the user is logged in, he can proceed to MainPage.jsx.
I am facing this error in console.log:
Uncaught SyntaxError: The requested module '/node_modules/.vite/deps/react-router-dom.js?v=6310222e' does not provide an export named 'Redirect' (at AuthRoute.jsx:3:17)
I also asked ChatGPT to help me fix this issue but his solutions didn't work.
I'd appreciate if you guys can help me correct the code.

Question about PrivateRoutes and to get navigated back to login page

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.

React component not updating when state is changed

I am having an issue with my navigation not being updated when a user is being logged in.
So my a portion of my App.js looks like so;
import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import Home from './views/Home';
import Login from './views/Login';
import Navigation from './components/Navigation';
function App() {
return (
<Router>
<React.Fragment>
<header className="header-global">
<Navigation />
</header>
<Route path="/" exact component={Home} />
<Route path="/login" component={Login} />
<Footer />
</React.Fragment>
</Router>
);
}
export default App;
In my Login.js file, I make a call to my API, check for valid details, if they are valid the response sets a token and also a expires at value into localStorage and then redirects to the homepage;
.then((response) => {
// Set token here
// set expires at here
// redirect to homepage after successful login
this.props.history.push("/");
This all works flawless, but in my Navigation.js file I want to change the link from Login to Logout but after the redirect it doesnt automatically do that .. I have to actually reload the page to see the Login change to Logout.
I have a seperate file called auth.js which has a function called isAuthenticated, this basically just checks that the token is there and valid and returns either true or false based on this.
This is my Navigation.js file (which i have cut down to only display whats needed), but i dont see anything wrong with it and I cant understand why its not automatically changing the value after the redirect.
import React, { Component } from 'react';
import auth from '../auth';
class Navigation extends Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false,
};
}
componentDidMount() {
if ( auth.isAuthenticated() ) {
this.setState({ isAuthenticated: true })
}
}
render() {
const { isAuthenticated } = this.state;
return (
{ isAuthenticated ? 'Logout' : 'Login' }
);
}
}
export default Navigation;
I have also tried using the componentWillMount method as well.
The following is the auth.isAuthenticated code (cut down)
isAuthenticated () {
if (this.isExpired()) {
return false
}
if (!this.getToken()) {
return false
}
return true
}
You need to add props history for Navigation:
import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import Home from './views/Home';
import Login from './views/Login';
import Navigation from './components/Navigation';
function App() {
return (
<Router>
<React.Fragment>
<header className="header-global">
<Navigation />
</header>
<Route path="/" exact component={Home} />
<Route path="/login" component={Login} />
<Footer />
</React.Fragment>
</Router>
);
}
export default App;
and in componentDidMount add this.props.history.push("/"):
import React, { PureComponent } from 'react';
import auth from '../auth';
class Navigation extends PureComponent {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false,
};
}
componentDidMount() {
if ( auth.isAuthenticated() ) {
this.setState({ isAuthenticated: true });
this.props.history.push("/");
}
}
render() {
const { isAuthenticated } = this.state;
return (
{ isAuthenticated ? 'Logout' : 'Login' }
);
}
}
export default withRouter(Navigation);
Example:

React PrivateRouter Implementation not working correctly

I have a small react app which has user login, I want to have a private route which will be protected, and only authenticated users can use it.
Here is my code.
App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
// Styling
import './App.css';
// Privat route
import PrivateRoute from './routes/PrivateRoute';
// Common
import Navigation from './components/common/Navigation';
// Components
import Layout from './components/Layout'
import Login from './components/Login';
import Home from './components/Home';
import Profile from './components/Profile';
export default () => (
<Router>
<Switch>
<Layout>
{/* Public routes */}
<Route exact path="/" component={ Home } />
<Route exact path="/login" component={ Login } />
{/* Private routes */}
<PrivateRoute exact path="/profile" component={ Profile } />
</Layout>
</Switch>
</Router>
);
PrivateRoute.js
import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';
import UserService from '../services/User';
export default class PrivateRoute extends React.Component {
state = {
isAuthenticated: null,
user: null
}
async componentDidMount(){
let isAuthenticated, user = null;
try{
user = await UserService.auth();
isAuthenticated = true;
}catch(e){
isAuthenticated = false;
}
this.setState({ isAuthenticated, user });
}
render() {
const { isAuthenticated, user } = this.state;
if(isAuthenticated === null){
return null;
}
return (
isAuthenticated ?
<Route path={this.props.path} component={this.props.component}/> :
<Redirect to={{ pathname: '/login', state: { from: this.props.location }}} />
);
}
}
Home.js
import React, { Component } from 'react';
export default class Home extends Component{
render(){
return (
<div>Home!</div>
);
}
}
I am constantly getting the error
Warning: You tried to redirect to the same route you're currently on: "/login"
even though I am in the home page which is has no business checking if user is authenticated.
I suspect this issue has something to do with my routes and the common layout I am trying to implement, but I cant find the problem.

React-Router noMatch causes asteroid.userId to return falsey

Notice the line Users.methods.isAuthed() and you can see that its calling !!asteroid.userId . My login form works fine, but I'm trying to make a react-router authorization wall which means the router will load the component when the authorization check returns true.
I've investigated further and Users.methods.isAuthed() returns false after passing a 404 url matching this guide: https://reacttraining.com/react-router/web/example/no-match
/src/components/PrivatePage.tsx
// almost identical to ./PrivateRoute.tsx
import * as React from 'react'
import { Redirect, Route } from 'react-router-dom'
import User from '../data/users'
import Page from './Page'
const PrivatePage = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
User.methods.isAuthed() ? ( **// after page 'notFound' this returns false**
<Page>
<Component {...props}/>
</Page>
) : (
<Redirect to={{
pathname: '/redirect',
state: { from: props.location }
}}/>
)
)}/>
)
export default PrivatePage
/src/data/users.tsx
import asteroid from '../asteroid/'
interface IUsers {
methods: {
isAuthed: () => boolean
}
}
const Users: IUsers = {
methods: {
isAuthed() {
const result = !!asteroid.userId
console.log({isAuthed: result})
return result
}
}
}
export default Users
/routes/App.tsx
import * as React from 'react'
import { Route, Switch } from 'react-router-dom'
import PrivatePage from '../components/PrivatePage'
import Login from './accounts/auth/'
import About from './root/About'
import Home from './root/Home'
import NotAuthorized from './root/NotAuthorized'
import NotFound from './root/NotFound'
interface IProps {}
interface IState {
isAuthorized: boolean
}
class App extends React.Component<IProps, IState> {
render() {
const Content = () => (
<div id='app-content'>
<Switch>
<Route path='/login' component={Login}/>
<Route path='/redirect' component={NotAuthorized}/>
<PrivatePage
path='/'
component={Home}
exact={true}
/>
<PrivatePage
path='/about'
component={About}
/>
<PrivatePage component={NotFound}/>
</Switch>
</div>
)
return (
<div id='app-container'>
<Content />
</div>
)
}
}
export default App

Categories

Resources