React refresh component on login - javascript

I have 2 components, NavBar which contains a login modal and the 'body' of page.
I want to detect when a user logs in and re-render the page based on that. How do I update the login prop in the second component when I log in using the modal of the first one?
A simplified version of the code to keep it short:
// NavBar.js
export default class NavBar extends Component {
constructor(props) {
super(props)
this.initialState = {
username: "",
password: "",
loginModal: false
}
this.handleLogin = this.handleLogin.bind(this)
}
handleLogin(e) {
e.preventDefault()
loginAPI.then(result)
}
render() {
return( <nav> nav bar with links and login button </nav>)
}
// Some random page
export default class Checkout extends Component {
constructor(props) {
super(props);
this.state = {
order_type: 'none',
loggedIn: false
}
this.Auth = new AuthService()
}
componentDidMount() {
if (this.Auth.loggedIn()) {
const { username, email } = this.Auth.getProfile()
this.setState({ loggedIn: true, email: email })
}
try {
const { order_type } = this.props.location.state[0]
if (order_type) {
this.setState({ order_type: order_type })
}
} catch (error) {
console.log('No package selected')
}
}
componentDidUpdate(prevProps, prevState) {
console.log("this.props, prevState)
if (this.props.loggedIn !== prevProps.loggedIn) {
console.log('foo bar')
}
}
render() {
return (
<section id='checkout'>
User is {this.state.loggedIn ? 'Looged in' : 'logged out'}
</section>
)
}
}
// App.js
function App() {
return (
<div>
<NavBar />
<Routes /> // This contains routes.js
<Footer />
</div>
);
}
// routes.js
const Routes = () => (
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/register" component={Register} />
<Route exact path="/registersuccess" component={RegisterSuccess} />
<Route exact path="/faq" component={FAQ} />
<Route exact path="/checkout" component={Checkout} />
<Route exact path="/contact" component={Contact} />
{/* <PrivateRoute exact path="/dashboard" component={Dashboard} /> */}
<Route path="/(notfound|[\s\S]*)/" component={NotFound} />
</Switch>
)

I would recommend using the react context API to store information about the logged in user.
See: https://reactjs.org/docs/context.html
Example
auth-context.js
import React from 'react'
const AuthContext = React.createContext(null);
export default AuthContext
index.js
import React, { useState } from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import AuthContext from './auth-context.js'
const AppWrapper = () => {
const [loggedIn, setLoggedIn] = useState(false)
return (
<AuthContext.Provider value={{ loggedIn, setLoggedIn }}>
<App />
</AuthContext.Provider>
)
}
ReactDOM.render(
<AppWrapper/>,
document.querySelector('#app')
)
Then inside any component you can import the AuthContext and use the Consumer component to check if the user is logged in order set the logged in state.
NavBar.js
import React from 'react'
import AuthContext from './auth-context.js'
const NavBar = () => (
<AuthContext.Consumer>
{({ loggedIn, setLoggedIn }) => (
<>
<h1>{loggedIn ? 'Welcome' : 'Log in'}</h1>
{!loggedIn && (
<button onClick={() => setLoggedIn(true)}>Login</button>
)}
</>
)}
</AuthContext.Consumer>
)
export default NavBar
HOC version
with-auth-props.js
import React from 'react'
import AuthContext from './auth-context'
const withAuthProps = (Component) => {
return (props) => (
<AuthContext.Consumer>
{({ loggedIn, setLoggedIn }) => (
<Component
loggedIn={loggedIn}
setLoggedIn={setLoggedIn}
{...props}
/>
)}
</AuthContext.Consumer>
)
}
export default withAuthProps
TestComponent.js
import React from 'react'
import withAuthProps from './with-auth-props'
const TestComponent = ({ loggedIn, setLoggedIn }) => (
<div>
<h1>{loggedIn ? 'Welcome' : 'Log in'}</h1>
{!loggedIn && (
<button onClick={() => setLoggedIn(true)}>Login</button>
)}
</div>
)
export default withAuthProps(TestComponent)
Alternatively if you have redux setup with react-redux then it will use the context API behind the scenes. So you can use the connect HOC to wrap map the logged in state to any component props.

Related

Why does Typescript in React not recognize the currentUser value from an exported Context with built in provider?

I'm attempting to have the project I'm working on update the user according with the onAuthStateChanged function from Firebase which is quite handy. So by following a tutorial I created a context with a built in provider which I wrapped my index file in:
import { AuthContextProvider } from './context/AuthContext';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<AuthContextProvider> // The wrapper
<React.StrictMode>
<App />
</React.StrictMode>
</AuthContextProvider>
);
This is my created context for user authentication:
import { createContext, useEffect, useState } from 'react';
import { onAuthStateChanged } from 'firebase/auth';
import { auth } from '../firebase.config';
export const UserContext = createContext({});
export const AuthContextProvider = ({ children }: any) => {
const [currentUser, setCurrentUser] = useState<any | null>({});
useEffect(() => {
const unsub = onAuthStateChanged(auth, (user) => {
setCurrentUser(user);
console.log(user);
});
return () => {
unsub();
};
}, []);
return (
<UserContext.Provider value={{ currentUser }}>
{children}
</UserContext.Provider>
);
};
And finally my actual app file where I get the error:
TS2339: Property 'currentUser' does not exist on type '{}'.
function App() {
const styles: Styles = {
wrapper: 'bg-purple-200 h-[100vh] w-[100vw] grid grid-cols-[minmax(100px,_250px)_1fr_minmax(150px,_250px)] grid-rows-[85%_minmax(50px,_350px)] absolute',
};
const { currentUser } = useContext(UserContext); //Error on this line
const saveElem = (
<div className={styles.wrapper}>
<LeftBar />
<ChatBody />
<RightBar />
<UserControlsContainer />
<ChatInput />
</div>
);
return (
<BrowserRouter>
<Routes>
<Route path='/'>
<Route index element={<ChatRooms />} />
<Route path='login' element={<LogInForm />} />
<Route path='signup' element={<SignUpForm />} />
</Route>
</Routes>
</BrowserRouter>
);
}
export default App;

scrolling has some problems

i using coreUi template for my reactJS project & in that when some component scrolling i can't have smooth scrolling which means i can scroll about bit first time and then again i have move courser bit and do the scrolling to go down of page..this is only happens with small screens (ex 1280px * 1024)
this is a gif file which showing the problem :
and here is the place where my all components are handling :
import React, { Component, Suspense, Fragment } from "react";
import { Route, BrowserRouter as Router } from "react-router-dom";
import * as router from "react-router-dom";
import { Container } from "reactstrap";
import { logout } from "../../actions/authActions";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import {
AppHeader,
AppSidebar,
AppSidebarFooter,
AppSidebarForm,
AppSidebarHeader,
AppSidebarMinimizer,
AppBreadcrumb2 as AppBreadcrumb,
AppSidebarNav2 as AppSidebarNav
} from "#coreui/react";
// sidebar nav config
import NavigationBar from "../../menu";
// routes config
import routes from "../../routes";
import { connect } from "react-redux";
import { loading } from "./LoadingComponent";
import ButtonPermission from "../../permission";
const DefaultHeader = React.lazy(() => import("./DefaultHeader"));
const Dashboard = React.lazy(() => import("./../../views/Dashboard/Dashboard"));
class DefaultLayout extends Component {
constructor() {
super();
this.currentNavigation = new NavigationBar().createMenu();
this.routes = new ButtonPermission().setPermission(routes);
}
signOut(e) {
e.preventDefault();
this.props.history.push("/login");
this.props.LOGOUT();
}
render() {
const divProps = Object.assign({}, this.props);
delete divProps.LOGOUT;
return (
<div className="app scroller">
<AppHeader fixed>
<Suspense fallback={loading()}>
<DefaultHeader onLogout={e => this.signOut(e)} />
</Suspense>
</AppHeader>
<div className="app-body">
<AppSidebar fixed display="lg">
<AppSidebarHeader />
<AppSidebarForm />
<Suspense>
<AppSidebarNav
navConfig={this.currentNavigation}
{...divProps}
router={router}
/>
</Suspense>
<AppSidebarFooter />
<AppSidebarMinimizer />
</AppSidebar>
<main className="main">
<AppBreadcrumb appRoutes={this.routes} router={router} />
<Container fluid>
<Suspense fallback={loading()}>
{this.routes.map((route, idx) => {
return route.component ? (
<Route
key={idx}
path={route.path}
exact={route.exact}
name={route.name}
render={props => (
<route.component {...props} {...route.props} />
)}
/>
) : (
<Fragment>
<Router
path="*"
name="home"
render={props => <Dashboard {...props} />}
/>
</Fragment>
////
////
);
})}
</Suspense>
<ToastContainer
autoClose={3000}
hideProgressBar
closeOnClick
pauseOnHover={false}
position="bottom-center"
/>
</Container>
</main>
</div>
</div>
);
}
}
const mapStateToProps = state => ({
error: state.error
});
const mapDispachToProps = dispach => {
return {
LOGOUT: () => dispach(logout())
};
};
export default connect(mapStateToProps, mapDispachToProps)(DefaultLayout);
can i get more smooth scrolling in my reactJS project please! Thank you!

Getting error while redirect to the home page in react

I was trying to restrict logged in user to access login page using following code
import React, { useEffect, useState } from "react"; import { Route }
from "react-router-dom"; import { Redirect } from "react-router-dom";
const UserLayoutRoute = ({ component: Component, ...rest }) => {
const [loggedIn, setLoggedIn] = useState(null); useEffect(() => {
if (localStorage.getItem("cachedValue") !== null) {
setLoggedIn(true);
} }, []); return loggedIn ? (
<Route
{...rest}
render={matchProps => (
<div className="App">
<section className="user-page">
<div className="">
<div className="">
<Component {...matchProps} />
</div>
</div>
</section>
</div>
)}
/> ) : (
<Redirect to="/" /> ); };
export default UserLayoutRoute;
With this code page keep on loading and its not rendering anything.
I also posted this issue in GitHub https://github.com/facebook/react/issues/17514
I think that maybe you can try other approach like this
import React from 'react';
import PropTypes from 'prop-types';
import { Route, Redirect } from 'react-router-dom';
const PrivateRouteComponent = ({ component: Component, isAuth, ...rest }) => (
<Route
{...rest}
render={props => (
isAuth
? <Component {...props} />
: <Redirect to="/login" />
)}
/>
);
PrivateRouteComponent.propTypes = {
component: PropTypes.any.isRequired,
isAuth: PropTypes.bool.isRequired,
};
export default PrivateRouteComponent;
And in the case the routes
<Switch>
<PrivateRouteComponent exact path="/" component={**ComponentName**} isAuth={isAuth} />
</Switch>
For the case that the isAuth props maybe you can change that for your condition

Redirect user to a Login Route on start of the application in react-redux

I am new to the react-redux. Here, what I want to do is that, when user hits the url lets say , localhost:3000 then user should directly move to the src/index.js localhost:3000/login page . And If user knows some routes and hits them without login then also it should redirect it to the
login page.
for that , what I have tried,
**Home.js**
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import App from './App';
import LoginComponent from './Components/loginComponent/LoginComponent';
class Home extends React.Component {
render() {
const rootPath = "/";
return (
<Switch>
<Route path={rootPath} component={App}/>
</Switch>
)
}
}
export default Home
**App.js**
import React from 'react';
import './App.css';
import { Provider } from 'react-redux';
import Main from './Containers/Main/Main';
import configureStore from './AppStore'
const store = configureStore()
class App extends React.Component {
render() {
return (
<Provider store={store}>
<div className="container-fluid">
<Main />
</div>
</Provider>
)
}
}
export default App
**Main.js**
import React from 'react';
import { Route, Redirect } from 'react-router';
import LoginComponent from '../../Components/loginComponent/LoginComponent';
import { LOGIN_REDIRECT_URL } from './../../Constants/AppConstants';
export default class Main extends React.Component {
constructor(props) {
super(props);
this.state = {
error: false,
hasUserLogedIn: false
}
}
render() {
const template =
!this.props.hasUserLogedIn
? (
<Route path="/*" render={(props) => <LoginComponent />}/>
) : (
<span>After login </span>
)
return (
<div>
{template}
</div>
)
}
}
function mapStateToProps(state) {
}
So, In the last file, I am doing that redirection, but it is not working. can any one help me with this ?
Because of the /* it is redirecting user to same view.
You can use public and private routes:
const PrivateRoute = ({ component: Component, ...rest, loggedIn }) => (
<Route
{...rest}
render={props =>
(loggedIn ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: LOGIN,
state: { from: props.location },
}}
/>
))
}
/>
);
const PublicRoute = ({ component: Component, ...rest, loggedIn}) => (
<Route
{...rest}
render={props =>
(!loggedIn ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: HOME,
state: { from: props.location },
}}
/>
))
}
/>
)

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