Updating redux state in react app.js file Authentication - reactjs

import React, { Component } from "react";
import { BrowserRouter, Route, Switch, Redirect } from "react-router-dom";
import { library } from "#fortawesome/fontawesome-svg-core";
import {
faHome,
faClock,
faTasks,
faStickyNote,
faCalendarWeek
} from "#fortawesome/free-solid-svg-icons";
import { connect } from "react-redux";
import store from "./store";
import { loadUser } from "./actions/authActions";
import Home from "./Home";
import SideNav from "./Components/SideNav";
import Recent from "./Components/Recent";
import TopBar from "./Components/TopBar";
import AddNote from "./AddNote";
import LogIn from "./Components/LogIn/LogIn.js";
import Register from "./Components/Register/Register";
import ToDo from "./Components/ToDo/ToDo";
import { timingSafeEqual } from "crypto";
library.add(faHome, faClock, faTasks, faStickyNote, faCalendarWeek);
class App extends Component {
componentDidMount() {
store.dispatch(loadUser());
}
componentDidUpdate(prevProps) {
if(this.props != this.prevProps) {
console.log("hello")
}
}
LogInContainer = () => {
return <Route path="/login" component={LogIn} />;
};
RegisterContainer = () => {
return <Route path="/register" component={Register} />;
};
DefaultContainer = () => {
return (
<div className="app_container">
<SideNav />
<TopBar />
<Route exact path="/" component={Home} />
<Route path="/recent" component={Recent} />
<Route path="/AddNote" component={AddNote} />
<Route path="/ToDo" component={ToDo} />
</div>
);
};
// Check for authenticaition
AuthRoute = ({ component: Component, props, ...rest }) => {
return (
<Route
{...rest}
render={props => {
if (this.props.auth.isAuthenticated) {
return <Component {...props} />;
}
else {
return (
<Redirect
to={{
pathname: "/login",
state: { from: this.props.location }
}}
/>
);
}
}}
/>
);
};
render() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/login" component={this.LogInContainer} />
<Route exact path="/register" component={this.RegisterContainer} />
<this.AuthRoute component={this.DefaultContainer} />
</Switch>
</BrowserRouter>
);
}
}
const mapStateToProps = (state) => ({
auth: state.auth
})
export default connect(mapStateToProps)(App);
How can app.js receive the new state from redux after logging in? The initial fetch it will get isAuthenticated = false. User then log ins but app.js isn't getting the new state. Am I implementing authenitcation wrong? comonentDidUpdate is throwing an error when trying to update props but feel like this is a bad way of doing it anyways

Related

i cant see it but is something wrong with'{this.props.promotions.filter(promotion=>promotion.featoured)[0]}'it keeps saying can't access property

I can't really see it but is there something wrong with
promotion={this.props.promotions.filter(promotion=>promotion.featured)[0]}
I keep getting this error, and I'm having trouble figuring it out:
TypeError: can't access property "filter", this.props.promotion is undefined. its suposed to me filtering an object in props.its so the state from promotions is sent i think
import React, { Component } from 'react';
import Home from './HomeComponent';
import { Switch, Route, Redirect, withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import Directory from './DirectoryComponent';
import CampsiteInfo from './CampsiteInfoComponent';
import Header from './HeaderComponent';
import Footer from './FooterComponent';
import Contact from './ContactComponent';
import About from './AboutComponent';
import { addComment } from '../redux/ActionCreators';
const mapStateToProps = state => {
return {
campsites: state.campsites,
comments: state.comments,
partners: state.partners,
promotion: state.promotion
}
}
const mapDispatchToProps = {
addComment: (campsiteId, rating, author, text) => (addComment(campsiteId, rating, author, text))
};
class Main extends Component {
render() {
const HomePage = () => {
return (
<Home
campsite={this.props.campsites.campsites.filter(campsite=>campsite.featured)[0]}
promotion={this.props.promotions.promotions.filter(promotions=>promotions.featured)[0]}
partner={this.props.partners.partners.filter(partners=> partners.featured)[0]}
/>
);
};
const CampsiteWithId = ({match}) => {
return (
<CampsiteInfo
campsite={this.props.campsites.filter(campsite=> campsite.id === +match.params.campsiteId)[0]}
comments={this.props.comments.filter(comment => comment.campsiteId === +match.params.campsiteId)}
addComment={this.props.addComment}
/>
);
};
return (
<div>
<Header />
<Switch>
<Route path='/home' component={HomePage} />
<Route exact path='/directory' render={()=> <Directory campsites={this.props.campsites} />} />
<Route path='/directory/:campsiteId' component={CampsiteWithId} />
<Route exact path='/contactus' component={Contact} />
<Route exact path='/aboutus' render={()=> <About partners={this.props.partners} />} />
<Redirect to='/home' />
</Switch>
<Footer />
</div>
);
}
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Main));
This could happen if props dont have promotions in the initial render. Do some validation like below. Do similar validations for campsite and partners if needed.
<Home
campsite={
this.props.campsites.campsites.filter((campsite) => campsite.featured)[0]
}
promotion={
this.props.promotions &&
Array.isArray(this.props.promotions.promotions) &&
this.props.promotions.promotions.length
? this.props.promotions.promotions.filter(
(promotions) => promotions.featured
)[0]
: ""
}
partner={
this.props.partners.partners.filter((partners) => partners.featured)[0]
}
/>;

Redirect not working with react router authenticated route

I'm attempting to create a private route based on the answers here, however it is not performing the redirect.
This is my private route component
import React, { Component, useContext } from "react";
import { Redirect, Route, RouteComponentProps, RouteProps } from "react-router-dom";
import { RootStoreContext } from "../stores/rootStore";
import { observer } from "mobx-react-lite";
const PrivateRoute: React.FC<RouteProps> = ({ children, ...rest }) => {
const rootStore = useContext(RootStoreContext);
const { isAuthenticated } = rootStore.msalStore;
return (
<Route
{...rest}
render={(props: RouteComponentProps<{}>) =>
isAuthenticated ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: "/", state: { from: props.location } }} />
)
}
/>
);
};
export default observer(PrivateRoute);
And this is my App.tsx
//Imports
const App: React.FC = () => {
return (
<>
<BrowserRouter>
<ThemeProvider theme={theme}>
<Route exact path="/" component={LoginPage} />
<Route path="/authcallback" component={AuthCallback} />
<PrivateRoute path="/home" component={HomePage} />
</ThemeProvider>
</BrowserRouter>
</>
);
};
export default App;
When I type /home in the browser, or create a test button that navigates to home, it loads the component even though isAuthenticated = false.
I know it's not related to the value of isAuthenticated in my mobx store as changing to const [isAuthenticated, setIsAuthenticated] = useState(false); doesn't work either. I also have no other instances of routing in my app.
What could be the issue here?
use Switch (from react-router-dom) to wrap routes,
import { Switch } from "react-router-dom";
const App: React.FC = () => {
return (
<>
<BrowserRouter>
<ThemeProvider theme={theme}>
<Switch>
<Route exact path="/" component={LoginPage} />
<Route path="/authcallback" component={AuthCallback} />
<PrivateRoute path="/home" component={HomePage} />
</Switch>
</ThemeProvider>
</BrowserRouter>
</>
);
};
export default App;
This discussion helped me
My solution...
https://codesandbox.io/s/modest-fire-6mj3i?file=/src/PrivateRoute.tsx:0-517
import * as React from "react";
import { BrowserRouter, Link, Route, Switch } from "react-router-dom";
import PrivateRoute from "./PrivateRoute";
import "./styles.css";
const Home: React.FC = () => {
return <div>Home</div>;
};
const Login: React.FC = () => {
return <div>Login</div>;
};
export default function App() {
return (
<BrowserRouter>
<ul>
<li>
<Link to="/home">Home</Link>
</li>
<li>
<Link to="/">Login</Link>
</li>
</ul>
<Switch>
<Route exact path="/" component={Login} />
<PrivateRoute redirectPath="/login" path="/home" component={Home} />
</Switch>
</BrowserRouter>
);
}
import { Redirect, Route, RouteProps } from "react-router";
import React, { useState } from "react";
export interface IPrivateRouteProps extends RouteProps {
redirectPath: string;
}
const PrivateRoute: React.FC<IPrivateRouteProps> = (props) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
return isAuthenticated ? (
<Route {...props} component={props.component} render={undefined} />
) : (
<Redirect to={{ pathname: props.redirectPath }} />
);
};
export default PrivateRoute;
If I click Home I get redirected to /login and the Home component is hidden
useState is only used for testing the authenticated state from within the component.

react functional component not get initialised

I have logout component(stateless) in that I want to delete access_token,
But my component not get initialised and there is no routing error as well,
Routing :
<Route path="/logout" component={LogoutComponante} />
logout component:
import React from 'react'
import { connect } from 'react-redux'
import { LOGOUT } from '../constant/constant'
function LogoutComponante(props){ console.log('in logout');
// props.logoutmethod();
// props.history.push("/")
return <h1>abc</h1>;
}
const mapStateToProps = state => {
return {
access_token : state.access_token
}
}
const mapDispatchToProps = dispatch => {
return {
logoutmethod : () => {
dispatch({ type : LOGOUT })
}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(LogoutComponante)
Routing details:
<Switch>
<Route exact path="/" component= {Home} />
<RouterManager/>
</Switch>
RouterManager component :
const RouterManager = (props) => {
if(props.access_token){
return (
<div>
<Route path="/logout" component={LogoutComponante} />
</div>
)
}else{
return (
<div>
<Route path="/register" component={Register} />
<Route path="/login" component={Register} />
</div>
)
}
}
when I visit /logout it returns nothing not even console.log('in logout'); is working.
What I am doing wrong?
Try wrapping your redux component with withRouter. Sometimes you will not see ok changes:
import { withRouter, connect } from 'react-redux'
export default withRouter(connect(mapStateToProps,mapDispatchToProps)(LogoutComponante))

Redux Authentication not using updated props?

privateRoute.js
import React, { Component } from "react";
import { BrowserRouter, Route, Switch, Redirect, withRouter} from "react-router-dom";
import { connect } from "react-redux";
function AuthRoute({ component: Component, isAuth, ...rest }) {
console.log(isAuth);
let test = false;
return (
<Route
{...rest}
render={props =>
isAuth.isAuthenticated === true ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
/>
);
}
const mapStateToProps = state => {
{
console.log(state);
return { isAuth: state.auth.isAuthenticated };
}
};
export default withRouter(connect(mapStateToProps, { pure: false })(AuthRoute));
App.js
import React, { Component } from "react";
import { BrowserRouter, Route, Switch, Redirect } from "react-router-dom";
import { library } from "#fortawesome/fontawesome-svg-core";
import PropTypes from "prop-types";
import {
faHome,
faClock,
faTasks,
faStickyNote,
faCalendarWeek
} from "#fortawesome/free-solid-svg-icons";
import { connect } from "react-redux";
import { loadUser, checkAuth } from "./actions/authActions";
import store from "./store";
import Home from "./Home";
import SideNav from "./Components/SideNav";
import Recent from "./Components/Recent";
import TopBar from "./Components/TopBar";
import AddNote from "./AddNote";
import LogIn from "./Components/LogIn/LogIn.js";
import Register from "./Components/Register/Register";
import ToDo from "./Components/ToDo/ToDo";
import AuthRoute from "./privateRoute";
library.add(faHome, faClock, faTasks, faStickyNote, faCalendarWeek);
class App extends Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false
};
}
static propTypes = {
isAuthenticated: PropTypes.bool
};
componentDidMount() {
store.dispatch(loadUser());
// this.props.isAuthenticated();
}
LogInContainer = () => {
return <Route path="/login" component={LogIn} />;
};
RegisterContainer = () => {
return <Route path="/register" component={Register} />;
};
DefaultContainer = () => {
return (
<div className="app_container">
<SideNav />
<TopBar />
<Route exact path="/" component={Home} />
<Route path="/recent" component={Recent} />
<Route path="/AddNote" component={AddNote} />
<Route path="/ToDo" component={ToDo} />
</div>
);
};
render() {
return (
<div>
<h1> {this.props.auth.isAuthenticated.toString()}</h1>
<BrowserRouter>
<Switch>
<Route exact path="/login" component={this.LogInContainer} />
<Route exact path="/register" component={this.RegisterContainer} />
<AuthRoute component={this.DefaultContainer} />
</Switch>
</BrowserRouter>
</div>
);
}
}
const mapStateToProps = state => {
return { auth: state.auth };
};
export default connect(mapStateToProps)(App);
When the user logins, an action will be dispatched to authentication the user. In redux dev tools, I can see the user authenticated.
Within privateRoute.js, mapStateToProps is always matching the initial state and not the updated state so isAuth never equates to true and I can't show the protected route?
I've been stuck on this for days, I feel like I'm implementing this wrong however looking at other examples I can't see what I am doing wrong.
The issue is how you are mapping state to props. It looks like your store state is structured as { auth: { isAuthenticated: boolean } }. However in the private route map state to props, you are trying to access effectively auth.isAuthenticated.isAuthenticated which will always be false/undefined. You need to go level higher in your state structure when mapping state to props. Try updating the private route component to:
import React, { Component } from "react";
import { BrowserRouter, Route, Switch, Redirect, withRouter } from "react-router-dom";
import { connect } from "react-redux";
function AuthRoute({ component: Component, isAuth, ...rest }) {
console.log(isAuth);
let test = false;
return (
<Route
{...rest}
render={props =>
isAuth.isAuthenticated === true ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
/>
);
}
const mapStateToProps = state => {
{
console.log(state);
return { isAuth: state.auth }; // change this line
}
};
export default withRouter(connect(mapStateToProps)(AuthRoute));

React Private Route higher order component?

I am trying to make a PrivateRoute component for react. Here is my higher order component. Can you tell me what is the problem with this.
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";
export default ({ component: Component, ...rest }) => {
class PrivateRoute extends React.Component {
render() {
console.log("This is private route called");
if (this.props.profile) {
return (
<Route
{...rest}
render={props =>
this.props.profile.loggedIn === true ? (
<Component {...props} />
) : (
<Redirect to="/login" />
)
}
/>
);
}
}
}
const mapStateToProps = state => ({
profile: state.profile
});
return connect(mapStateToProps)(PrivateRoute);
};
Here's how you can accomplish a protected route via a protected route component.
Working example: https://codesandbox.io/s/yqo75n896x
containers/RequireAuth.js
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";
import ShowPlayerRoster from "../components/ShowPlayerRoster";
import ShowPlayerStats from "../components/ShowPlayerStats";
import Schedule from "../components/Schedule";
const RequireAuth = ({ match: { path }, isAuthenticated }) =>
!isAuthenticated ? (
<Redirect to="/signin" />
) : (
<div>
<Route exact path={`${path}/roster`} component={ShowPlayerRoster} />
<Route path={`${path}/roster/:id`} component={ShowPlayerStats} />
<Route path={`${path}/schedule`} component={Schedule} />
</div>
);
export default connect(state => ({
isAuthenticated: state.auth.isAuthenticated
}))(RequireAuth);
routes/index.js
import React from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import Home from "../components/Home";
import Header from "../containers/Header";
import Info from "../components/Info";
import Sponsors from "../components/Sponsors";
import Signin from "../containers/Signin";
import RequireAuth from "../containers/RequireAuth";
import rootReducer from "../reducers";
const store = createStore(rootReducer);
export default () => (
<Provider store={store}>
<BrowserRouter>
<div>
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/info" component={Info} />
<Route path="/sponsors" component={Sponsors} />
<Route path="/protected" component={RequireAuth} />
<Route path="/signin" component={Signin} />
</Switch>
</div>
</BrowserRouter>
</Provider>
);
Or, if you want something that wraps all routes (instead of having to specify a protected route component). Then you can do something like the below.
Working example: https://codesandbox.io/s/5m2690nn6n
components/RequireAuth.js
import React, { Component, Fragment } from "react";
import { withRouter } from "react-router-dom";
import Login from "./Login";
import Header from "./Header";
class RequireAuth extends Component {
state = { isAuthenticated: false };
componentDidMount = () => {
if (!this.state.isAuthenticated) {
this.props.history.push("/");
}
};
componentDidUpdate = (prevProps, prevState) => {
if (
this.props.location.pathname !== prevProps.location.pathname &&
!this.state.isAuthenticated
) {
this.props.history.push("/");
}
};
isAuthed = () => this.setState({ isAuthenticated: true });
unAuth = () => this.setState({ isAuthenticated: false });
render = () =>
!this.state.isAuthenticated ? (
<Login isAuthed={this.isAuthed} />
) : (
<Fragment>
<Header unAuth={this.unAuth} />
{this.props.children}
</Fragment>
);
}
export default withRouter(RequireAuth);
routes/index.js
import React from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import Home from "../components/Home";
import Players from "../components/Players";
import Schedule from "../components/Schedule";
import RequireAuth from "../components/RequireAuth";
export default () => (
<BrowserRouter>
<RequireAuth>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/players" component={Players} />
<Route path="/schedule" component={Schedule} />
</Switch>
</RequireAuth>
</BrowserRouter>
);
Or, if you want something a bit more modular, where you can pick and choose any route, then you can create a wrapper HOC. See this example (while it's written for v3 and not for authentication, it's still the same concept).
It looks like your render function's only return is inside of an if block, so its returning null. You need to fix the logic to just return the Route and make profile a required prop in your proptypes check instead of using an if block.
PrivateRoute.propTypes = {
profile: PropTypes.object.isRequired
};

Resources