Routing to different tabs in ReactJS - reactjs

There is a HeaderComponent and a BodyComponent in my project.
This is the TabComponent from the HeaderComponent:
TabComponent
import React, {Component} from 'react'
import Context from '../../provider'
import {Nav, NavItem, NavLink} from 'reactstrap'
import {Redirect} from 'react-router-dom'
import classnames from 'classnames'
export default class TabComponent extends Component {
render() {
return (
<Context.Consumer>
{context => (
<Nav tabs color='primary'>
<NavItem>
<NavLink
className={classnames({ active: context.activeTab === '1' })}
onClick={() => { context.toggleTab('1'); }}
>
Home
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={classnames({ active: context.activeTab === '2' })}
onClick={() => { context.toggleTab('2'); }}
>
Popular
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={classnames({ active: context.activeTab === '3' })}
onClick={() => { context.toggleTab('3'); }}
>
All
</NavLink>
</NavItem>
</Nav>
)}
</Context.Consumer>
)
}
}
BodyComponent
import React, {Component} from 'react'
import Context from '../provider'
import SwitchTab from './OtherComponents/SwitchTab'
import { BrowserRouter, Route, Redirect } from "react-router-dom";
export default class BodyComponent extends Component {
render() {
return (
<Context.Consumer>
{context => {
return (
<React.Fragment>
<BrowserRouter>
<React.Fragment>
<Route exact path='/' render={() => <Redirect to='/home/' /> } />
<Route eaxt path='/home/' render={() => context.activetab='1'} />
<Route eaxt path='/popular/' render={() => context.activetab='2'} />
<Route eaxt path='/all/' render={() => context.activetab='3'} />
</React.Fragment>
</BrowserRouter>
<SwitchTab />
</React.Fragment>
)
}}
</Context.Consumer>
)
}
}
This is my provider.js which has the Context
import React, {Component} from 'react';
const Context = React.createContext();
class Provider extends Component {
state = {
loggedIn: false,
username: '',
password: '',
loginModalOpen: false,
signupModalOpen: false,
navbarOpen: false,
activeTab: '3',
toggleLoggedIn: () => {
this.setState({loggedIn: !this.state.loggedIn});
},
toggleLoginModal: () => {
this.setState({loginModalOpen: !this.state.loginModalOpen});
},
toggleSignupModal: () => {
this.setState({signupModalOpen: !this.state.signupModalOpen});
},
toggleNavbar: () => {
this.setState({navbarOpen: !this.state.navbarOpen})
},
toggleTab: (tab) => {
if(this.state.activeTab !== tab) {
this.setState({activeTab: tab});
}
}
}
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
)
}
}
export {Provider};
export default Context;
And, this is my SwitchTab
import React, {Component} from 'react'
import Context from "../../../provider";
import { Container, TabContent, TabPane } from "reactstrap";
import Home from '../../Content/Home'
import Popular from '../../Content/Popular'
import All from '../../Content/All'
export default class SwitchTab extends Component {
render() {
return (
<Context.Consumer>
{context => {
return (
<Container>
<TabContent activeTab={context.activeTab}>
<TabPane tabId="1">
<Home />
</TabPane>
<TabPane tabId="2">
<Popular />
</TabPane>
<TabPane tabId="3">
<All />
</TabPane>
</TabContent>
</Container>
)
}}
</Context.Consumer>
)
}
}
The functionality that I want to achieve is:
Whenever the URL is '/', redirect to '/home/'.
Whenever the URL is '/home/', change the activeTab from the
Context and make SwitchTab re-render so that home tab gets
opened.
The current working state is whenever I click on a tab, the content changes but the URL remains as /home/. If the Change the URL to /popular/ or /all/, it doesn't change the content.

The error clearly states what is wrong with your problem, you need to wrap your Routes within a div as a Router accepts only one child element.
Also in order to set the state in Provider you need to use setState or provide a handler
class Provider extends Component {
state = {
loggedIn: false,
username: '',
password: '',
loginModalOpen: false,
signupModalOpen: false,
navbarOpen: false,
activeTab: '3',
setActiveTab: (tab) => {
this.setState({activeTab: tab});
}
toggleLoggedIn: () => {
this.setState({loggedIn: !this.state.loggedIn});
},
toggleLoginModal: () => {
this.setState({loginModalOpen: !this.state.loginModalOpen});
},
toggleSignupModal: () => {
this.setState({signupModalOpen: !this.state.signupModalOpen});
},
toggleNavbar: () => {
this.setState({navbarOpen: !this.state.navbarOpen})
},
toggleTab: (tab) => {
if(this.state.activeTab !== tab) {
this.setState({activeTab: tab});
}
}
}
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
)
}
}
also since you can't set state in render directly, you would need to create a component that handles this case
class Handler extends React.Component {
componentDidMount() {
this.props.setActiveTab(this.props.activeTab);
}
render() {
return null;
}
}
and your Router config would look like
<BrowserRouter>
<div>
<Route exact path='/' render={() => <Redirect to='/home/' /> } />
<Route exact path='/home/' render={() => <Handler setActiveTab={setActiveTab} activeTab={'1'} />}/>
<Route exact path='/popular/' render={() => <Handler setActiveTab={setActiveTab} activeTab={'2'} />}/>
<Route exact path='/all/' render={() => <Handler setActiveTab={setActiveTab} activeTab={'3'} />}/>
</div>
</BrowserRouter>

Related

Routing in a nested React component

I ask you not to throw stones, because everyone once studied) The bottom line is this: I am writing a wishlist for myself and my friends, and I got stuck at a seemingly very stupid moment. The nested component is a header with navigation tabs and an exit button. While I am implementing the framework of the application, therefore, authorization occurs simply by loggedInUser /!loggedInUser. Actually, when you click on the exit button, an empty string is dispatched in loggedInUser and history.push ('/ login'). In the debugger, I see that the dispatch is happening and the location is pushed to the history, but for some reason, the rendering condition will not be fulfilled. I ask the help of knowledgeable people. I suppose that I messed up with routing somewhere, since I read that BrowserRouter for some reason is not used, but without it nothing works at all. In general, thanks in advance!
Entry:
const history = createBrowserHistory()
ReactDOM.render(
<Router history={history}>
<Provider store={store}>
<App />
</Provider>
</Router>,
document.getElementById('root')
);
Routing component:
interface AppProps {
loggedInUser: string;
}
class App extends React.Component<AppProps & RouteComponentProps> {
state = {
loggedInUser: ""
}
render() {
const history = this.props
return (
<>
<BrowserRouter>
<Segment>
<Switch>
<Route history={history} path='/login' render={() => (!this.props.loggedInUser ? <LoginPage /> : <Redirect to="/account" />)}/>
<Route history={history} path='/account' render={() => (this.props.loggedInUser ? <AccountPage/> : <Redirect to="/login" />)}/>
<Route history={history} path='/friendslist' render={() => (this.props.loggedInUser ? <FriendsList/> : <Redirect to="/login" />)}/>
<Redirect from='/' to='/login' />
</Switch>
</Segment>
</BrowserRouter>
</>
)
}
}
const mapStateToProps = (state: StateInterface): AppProps => ({
loggedInUser: state.loggedInUser
})
export default connect(mapStateToProps)(withRouter(App))
Nested component (it is rendered in each of the routed components):
interface HeaderProps extends HeaderPropsFromState{
activeItem: string;
}
interface HeaderPropsFromState{
loggedInUser: string;
}
class Header extends React.Component<HeaderProps & RouteComponentProps> {
state = {
activeItem: this.props.activeItem,
}
handleItemClick = (e: any, { name }: any) => this.setState({ activeItem: name })
render() {
const { activeItem } = this.state
const { match, history } = this.props
return (
<Menu pointing>
<Menu.Item
name='Friends'
active={activeItem === 'Friends'}
onClick={this.handleItemClick}
as={Link}
to="/friendslist"
/>
<Menu.Item
name='Account'
active={activeItem === 'Account'}
onClick={this.handleItemClick}
as={Link}
to="/account"
/>
{activeItem === 'Friends' &&
<Menu.Menu position='right'>
<Menu.Item>
<Input icon='users' iconPosition='left' placeholder='Search users...' />
{/* TODO: create function to filter by friend's name */}
</Menu.Item>
</Menu.Menu>
}
{activeItem === 'Account' &&
<Menu.Menu position='right'>
<Menu.Item>
<Button basic
color='black'
onClick={() => {
console.log(this.props.loggedInUser)
store.dispatch(setLoggedInUser({username: ""}))
history.push('/login')
}}
>Exit</Button>
{/* TODO: create function to exit from account */}
</Menu.Item>
</Menu.Menu>
}
</Menu>
)
}
}
const mapStateToProps = (state: StateInterface): HeaderPropsFromState => ({
loggedInUser: state.loggedInUser
})
export default connect(mapStateToProps)(withRouter(Header))
UPD: Component that includes the header component.
class FriendsList extends React.Component{
users = [...users objects]
render() {
const usersList = this.users.map((user: User, index: number) =>
<OneFriendWishes user={user} key={index}/>
)
return (
<>
<Header activeItem={"Friends"}/>
{usersList}
</>
)
}
}
export default FriendsList

How render form on new page using React NavLink?

I have the following NavLink in my React Sidebar component that successfully links to an add-folder new page; however, I'm unable to render an AddFolder form on this new page (I've successfully tested that the AddFolder form renders in the Sidebar component, but that's not what I want). I've tried numerous things to resolve this, including using "component={AddFolder}", "render={={() => { return }}". Most recently I tried adding an onClick which doesn't work either.
<section className="AddFolder_Section">
<NavLink
className="AddFolder_Button"
tag={Link}
to={'/add-folder'}
type='button'
onClick={() => this.AddFolder}
>
Add Folder
</NavLink>
</section>
Are there pointers that you can give me on what might work here? Thank you.
Here are the entire contents of my sidebar.js file:
import React, { Component } from 'react'
import { NavLink, Route, Link } from 'react-router-dom'
import NotesContext from './notesContext'
import AddFolder from './addFolder'
import './sidebar.css'
class Sidebar extends Component {
static contextType = NotesContext
render() {
let notesContext = this.context
const selectedFolder = this.props.match.params.folder_id || {}
return (
<section className="Sidebar">
{notesContext.folders.map(folder => {
return(
<section key={folder.id} className={(selectedFolder && selectedFolder === folder.id)? "SelectedFolder": "Folder"}>
<NavLink className="Folder_Link"
tag='button'
role='link'
to={'/folder/' + folder.id}>
{folder.name}
</NavLink>
</section>
)
})}
<section className="AddFolder_Section">
<NavLink
className="AddFolder_Button"
tag={Link}
to={'/add-folder'}
type='button'
onClick={() => this.AddFolder}
>
Add Folder
</NavLink>
<Route
path='/add-folder'
render={(props) =>
<AddFolder
{...props}
/>
}
/>
</section>
</section>
);
}
}
export default Sidebar;
As I understand your question: AddFolder is your "form" component.
You need to first import your AddFolder component on the parent component that you want to render the form on.
import AddFolder from '../somePath/AddFolder';
Then on your render() function, place the <Route> and simply render the AddFolder component when you are on the add-folder path. Pass props if needed.
<Route
path='/add-folder'
render={(props) =>
<AddFolder
{...props}
/>
}
/>
It turns out I had a typo in the Route defined in my App.js. I needed 'add-folder' instead of 'add_folder'. Now the Route in App works with the NavLink in Sidebar. Yeah!
Here is the App.js:
import React, { Component } from 'react'
import { Route, Switch } from 'react-router-dom'
import Header from './header.js'
import Main from './main.js'
import MainDetail from './mainDetail.js'
import Sidebar from './sidebar.js'
import SidebarDetail from './sidebarDetail.js'
import NotesContext from './notesContext'
import './App.css'
import config from './config'
import AddFolder from './addFolder'
import AddNote from './addNote'
class App extends Component {
state = {
folders: [],
notes: [],
error: null,
};
setData = (notes, folders) => {
this.setState({
notes,
folders,
error: null
})
}
deleteNote = note_id => {
fetch(config.API_ENDPOINT + "/notes/" + note_id, {
method: 'DELETE',
headers: {
'content-type': 'application/json'
}
})
.then(response => response.json())
.then(result => {
const newNotes = this.state.notes.filter(note => note.id !== note_id)
this.setState({
notes: newNotes
})
})
}
addFolder = (name, id) => {
this.setState({
folders: [...this.state.folders, {name, id}]
})
}
componentDidMount() {
Promise.all([
fetch(config.API_ENDPOINT + "/notes"),
fetch(config.API_ENDPOINT + "/folders")
])
.then(responses => {
return Promise.all(responses.map(function (response) {
return response.json();
}));
})
.then(results => {
this.setData(results[0], results[1])
})
.catch(error => this.setState({ error }))
}
render() {
const contextValue = {
notes: this.state.notes,
folders: this.state.folders,
deleteNote: this.deleteNote,
addFolder: this.addFolder
}
//console.log(this.state.notes)
return (
<NotesContext.Provider value={contextValue}>
<section className="App">
<Switch>
<Route
exact path="/"
component={Header}
/>
<Route
path="/folder/:folder_id"
component={Header}
/>
<Route
path="/note/:note_id"
component={Header}
/>
</Switch>
<section className="Section_Sidebar">
<Switch>
<Route
exact path="/"
component={Sidebar}
/>
<Route
path="/folder/:folder_id"
component={Sidebar}
/>
<Route
path="/note/:note_id"
component={SidebarDetail}
/>
</Switch>
</section>
<section className="Section_Main">
<Switch>
<Route
exact path="/"
component={Main}
/>
<Route
path="/folder/:folder_id"
component={Main}
/>
<Route
path="/note/:note_id"
component={MainDetail}
/>
<Route
path="/add-folder"
component={AddFolder}
/>
<Route
path="/add-note"
component={AddNote}
/>
</Switch>
</section>
</section>
</NotesContext.Provider>
);
}
}
export default App;
This is the updated Sidebar.js:
import React, { Component } from 'react'
import { NavLink, Route, Link } from 'react-router-dom'
import NotesContext from './notesContext'
import AddFolder from './addFolder'
import './sidebar.css'
class Sidebar extends Component {
static contextType = NotesContext
render() {
let notesContext = this.context
const selectedFolder = this.props.match.params.folder_id || {}
return (
<section className="Sidebar">
{notesContext.folders.map(folder => {
return(
<section key={folder.id} className={(selectedFolder && selectedFolder === folder.id)? "SelectedFolder": "Folder"}>
<NavLink className="Folder_Link"
tag='button'
role='link'
to={'/folder/' + folder.id}>
{folder.name}
</NavLink>
</section>
)
})}
<section className="AddFolder_Section">
<NavLink
className="AddFolder_Button"
tag={Link}
to={'/add-folder'}
type='button'
>
Add Folder
</NavLink>
</section>
</section>
);
}
}
export default Sidebar;

How to hide nav bar component in reactjs using protected route

Hi there i have created a protected route in and passing navbar as parent component. then i passing child components in protected rout i want to hide navbar in some component on some action
Here is my protected.router.js code
import React from "react";
import { Route, Redirect } from "react-router-dom";
import Navbar from './component/Layouts/Navbar';
export const ProtectedRoute = ({
component: Component,
...rest
}) => {
return (
<Route
{...rest}
render={props => {
if (localStorage.getItem("loggedAsli") === "1") {
return <div> <Navbar/>
<Component {...props} /> </div>;
} else {
return (
<Redirect
to={{
pathname: "/login",
state: {
from: props.location
}
}}
/>
);
}
}}
/>
);
};
And this my App.js code
import React from "react";
import { BrowserRouter, Route } from "react-router-dom";
import { ProtectedRoute } from "./protected.route";
import Learn from "./component/Learn/Learn";
class App extends React.Component {
constructor(props) {
super();
this.updateUserLoginSetting = this.updateUserLoginSetting.bind(this);
this.state = {
userId: "",
instituteId: ""
};
}
updateUserLoginSetting = (userId, instituteId) => {
this.setState({ userId: userId, instituteId: instituteId });
};
render() {
return (
<BrowserRouter>
<div className="App">
<Route render={props => <Login />} exact path="/login" />
<ProtectedRoute exact path="/Learn" component={Learn} />
</div>
</BrowserRouter>
);
}
}
export default App;
How i can hide navbar in Learn Component
Please guide me.
is there any global state handling
You could just pass a prop (e.g. showNav) and use it inside ProtectedRoute
export const ProtectedRoute = ({
component: Component,
showNav = true, // added showNav prop
...rest
}) => {
return (
<Route
{...rest}
render={props => { // check if should showNav
if (localStorage.getItem("loggedAsli") === "1" && showNav) {
return <div> <Navbar/>
<Component {...props} /> </div>;
} else {
return (
<Redirect
to={{
pathname: "/login",
state: {
from: props.location
}
}}
/>
);
}
}}
/>
);
};
And pass false when it's Learn
// pass showNav as false to hide nav bar
<ProtectedRoute showNav={false} exact path="/Learn" component={Learn} />

Pass state from one component to another stateless component

I tried to summarize my problem in the code below. My real code it is too big, so I developed another similar code in way to solve this problem.
I have a loggin page where the user has to type "True" or "False" to update the state fom this component.
I need to pass this state to the "Route" component, that will verify what page is going to be rendered. If the parameter received from the Login component is "True", then Home page will be rendered. If it is "False" Login page will be rendered.
From my understanding, I have to pass props from childreen to parent component, but I am not being able to solve this problem.
App.jsx (Component)
import React from 'react'
import { BrowserRouter } from 'react-router-dom'
import Routes from './Routes'
export default props =>
<BrowserRouter>
<div>
<Routes />
</div>
</BrowserRouter>
Routes.jsx (Component)
import React from 'react'
import { Switch, Route, Redirect} from 'react-router'
import Login from './Login';
import Home from './Home';
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props =>
isAuthenticated() ? (
<Component {...props} />
): (
<Redirect to={{pathname: "/login", state: {from: props.location }}} />
)}
/>
)
const Routes = () =>
<Switch>
<PrivateRoute path='/home' component={Home} />
<Route exact path='/login' component={Login} />
<Redirect from='*' to='/home' />
</Switch>
export default Routes;
Home.jsx (Component)
import React, { Component } from 'react'
export default class Home extends Component {
render (){
return (
<h1>This is the HOME page</h1>
);
}
}
Login.jsx (Component)
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import Routes from './Routes'
export default class Login extends Component{
constructor(props){
super(props);
this.state = {
userLoggedIn: false
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(e) {
e.preventDefault()
let stateName = e.target.name
let stateValue = e.target.value
console.log(e.target, e.target.value)
this.setState({ [stateName]: stateValue})
}
render(){
console.log('esse estado é',this.state.userLoggedIn)
return(
<div>
<div>This is the Login Page</div>
<label>State Test</label>
<input placeholder="true or false" onChange={e => this.handleChange(e)}></input>
<Link to={{pathname: "/home"}}>
<button >Go To Home Page</button>
</Link>
</div>
)
}
}
What do I expect?
When the user type "True" in the Login page, Home page must be rendered.
When the user type "False" in the Login page, Login page must be rendered.
Here is the working code and codesandbox link
If user enters false, then he will not be redirected as he is already on Login page.
import React, { Component } from "react";
import {
BrowserRouter as Router,
Route,
Link,
Redirect,
withRouter
} from "react-router-dom";
function AuthExample() {
return (
<Router>
<div>
<AuthButton />
<ul>
<li>
<Link to="/home">Home Page</Link>
</li>
</ul>
<Route path="/login" component={Login} />
<PrivateRoute path="/home" component={Home} />
</div>
</Router>
);
}
const fakeAuth = {
isAuthenticated: false,
authenticate(cb) {
this.isAuthenticated = true;
setTimeout(cb, 100); // fake async
},
signout(cb) {
this.isAuthenticated = false;
setTimeout(cb, 100);
}
};
const AuthButton = withRouter(({ history }) =>
fakeAuth.isAuthenticated ? (
<p>
Welcome!{" "}
<button
onClick={() => {
fakeAuth.signout(() => history.push("/"));
}}
>
Sign out
</button>
</p>
) : (
<p>You are not logged in.</p>
)
);
function Home() {
return <h3>This is the HOME page</h3>;
}
function PrivateRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
render={props =>
fakeAuth.isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
/>
);
}
class Login extends Component {
state = {
redirectToReferrer: false,
input: ""
};
login = e => {
e.preventDefault();
if (this.state.input === "true") {
fakeAuth.authenticate(() => {
this.setState({ redirectToReferrer: true });
});
} else {
this.setState({ redirectToReferrer: true });
}
};
handleChange = ({ target }) => {
this.setState({ [target.name]: target.value });
};
render() {
let { from } = this.props.location.state || { from: { pathname: "/" } };
let { redirectToReferrer } = this.state;
if (redirectToReferrer) return <Redirect to={from} />;
return (
<div>
<div>This is the Login Page</div>
<label>State Test</label>
<br />
<input
placeholder="true or false"
name={"input"}
value={this.state.input}
onChange={this.handleChange}
/>
<br />
<button onClick={this.login}>Go To Home Page</button>
</div>
);
}
}
export default AuthExample;
Hope that helps!!!

Log in page does not render with React Router ProtectedRoute

I have a react router app:
export default () => (
<Router basename={process.env.REACT_APP_BASENAME || ""}>
<div>
{routes.map((route, index) => {
return (
<PrivateRoute
key={index}
path={route.path}
exact={route.exact}
component={props => {
return (
<route.layout {...props}>
<route.component {...props} />
</route.layout>
);
}}
/>
);
})}
</div>
</Router>
);
and this will render dfferent views based on the route clicked. the routes will render based on this object in a routes.js file:
export default [
{
path: "/login",
layout: DefaultLayout,
component: LogIn
}, .....]
To build in some authentication, I defined a PrivateRoute as:
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={(props) => (
fakeAuth.isAuthenticated === true
? <Component {...props} />
: <Redirect to='/login' />
)} />
)
however, when i set the app as using PrivateRoute instead of normal Route (in the first snippet), the redirect does not use the routes object. How do I change the PrivateRoute const for a log in page reflect my original React Route architecture? what is the best practice?
Your code looks fine, but since you said your routes object is not understood by react-router maybe there is the case that your components aren't defined properly. For example, your components may be defined after the object is created. In that case, when that object is created, it will refer to undefined components. I made this mistake once, so I am just sharing what possibly went wrong.
Here is an example:
import ReactDOM from "react-dom";
import React, { Component } from "react";
import {
BrowserRouter as Router,
Route,
Link,
Redirect,
withRouter
} from "react-router-dom";
function Public() {
return <h3>Public</h3>;
}
function Protected() {
return <h3>You can see protected content</h3>;
}
class Login extends Component {
state = { redirectToReferrer: false };
login = () => {
fakeAuth.authenticate(() => {
this.setState({ redirectToReferrer: true });
});
};
render() {
let { from } = this.props.location.state || { from: { pathname: "/" } };
let { redirectToReferrer } = this.state;
if (redirectToReferrer) return <Redirect to={from} />;
return (
<div>
<p>You must log in to view the page at {from.pathname}</p>
<button onClick={this.login}>Log in</button>
</div>
);
}
}
const routes = [
{
path: "/public",
component: Public,
private: false
},
{
path: "/login",
component: Login,
private: false
},
{
path: "/protected",
component: Protected,
private: true
}
];
function AuthExample() {
return (
<Router>
<div>
<AuthButton />
<ul>
<li>
<Link to="/public">Public Page</Link>
</li>
<li>
<Link to="/protected">Protected Page</Link>
</li>
</ul>
{routes.map((route, index) => {
if (route.private)
return (
<PrivateRoute
key={index}
path={route.path}
exact={route.exact}
component={props => {
return <route.component {...props} />;
}}
/>
);
return (
<Route
key={index}
path={route.path}
exact={route.exact}
component={props => {
return <route.component {...props} />;
}}
/>
);
})}
</div>
</Router>
);
}
const fakeAuth = {
isAuthenticated: false,
authenticate(cb) {
this.isAuthenticated = true;
setTimeout(cb, 100); // fake async
},
signout(cb) {
this.isAuthenticated = false;
setTimeout(cb, 100);
}
};
const AuthButton = withRouter(({ history }) =>
fakeAuth.isAuthenticated ? (
<p>
Welcome!{" "}
<button
onClick={() => {
fakeAuth.signout(() => history.push("/"));
}}
>
Sign out
</button>
</p>
) : (
<p>You are not logged in.</p>
)
);
function PrivateRoute(props) {
const { component: Component, ...rest } = props;
return (
<Route
{...rest}
render={props =>
fakeAuth.isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
/>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<AuthExample />, rootElement);
Notice Public, Protected and Login components are defined above the routes object. Defining them after the routes will result in errors.
I suggest to change your private route as following
const PrivateRoute = ({ component: Component, ...rest }) => fakeAuth.isAuthenticated === true ? (
<Route {...rest} component={component}
)} />
) : <Redirect to='/login' />;

Resources