I am passing in the state - IsLoggedIn from the App component to the Header component. But, whenever the onClick event triggers, the IsLoggedIn should change it's state. But, this does not seem to be happening. I don't know why this keeps on happening? Does the App component re render itself with the isLoggedIn being false everytime?
App.js
import React, { Component } from 'react';
import { BrowserRouter, Route, Link } from "react-router-dom";
import Header from './Header';
import DashBoard from './Dashboard';
import Home from './Home';
class App extends Component {
constructor() {
super();
this.state = {
isLoggedIn: false
}
}
onEventClick = () => {
if (this.state.isLoggedIn) {
this.setState({isLoggedIn: false});
}
else {
this.setState({isLoggedIn: true});
}
}
render() {
return (
<BrowserRouter>
<div className="container">
<Header onEventClick={this.onEventClick} LoggedInState={this.state.isLoggedIn}/>
<Route path="/" exact={true} component={Home}/>
<Route path="/dashboard" exact={true} component={DashBoard}/>
</div>
</BrowserRouter>
)
}
}
export default App;
Header.js
import React, { Component } from 'react';
import { Link } from "react-router-dom";
class Header extends Component {
constructor(props) {
super(props);
}
renderContent() {
if (this.props.LoggedInState) {
return (
<li>
<a onClick={this.props.onEventClick} href="/api/logout" style={{borderRadius: '12px'}} className="waves-effect waves-light btn-small green darken-1">
Log Out
</a>
</li>
);
}
else {
return (
<li>
<a href="/auth/spotify" onClick={this.props.onEventClick} style={{borderRadius: '12px'}} className="waves-effect waves-light btn green darken-1">
Log in with Spotify
</a>
</li>
);
}
}
render() {
return (
<nav>
<div className="nav-wrapper blue-grey darken-4" style={{paddingLeft: '4px'}}>
<Link to={this.props.LoggedInState ? '/dashboard' : '/'} className="brand-logo">TuneIn</Link>
<ul className="right">
{this.renderContent()}
</ul>
</div>
</nav>
);
}
}
export default Header;
The reason why your state is not updating is that you have an anchor tag which after clicking on it causes the page to reload to the next page, therefore, your state resets back to the default false. Do this instead.
In your header.js
import React, { Component } from "react";
import { Link } from "react-router-dom";
class Header extends Component {
constructor(props) {
super(props);
}
renderContent() {
if (this.props.LoggedInState) {
return (
<li>
<Link
to="/api/logout"
onClick={this.props.onEventClick}
style={{ borderRadius: "12px" }}
className="waves-effect waves-light btn-small green darken-1"
>
Log Out
</Link>
</li>
);
} else {
return (
<li>
<Link
to="/auth/spotify"
onClick={this.props.onEventClick}
style={{ borderRadius: "12px" }}
className="waves-effect waves-light btn green darken-1"
>
Log in with Spotify
</Link>
</li>
);
}
}
render() {
return (
<nav>
<div
className="nav-wrapper blue-grey darken-4"
style={{ paddingLeft: "4px" }}
>
<Link
to={this.props.LoggedInState ? "/dashboard" : "/"}
className="brand-logo"
>
TuneIn
</Link>
<ul className="right">{this.renderContent()}</ul>
</div>
</nav>
);
}
}
export default Header;
Alternatively, if you want to keep your header.js unchanged, you could use local storage as a check to update your state accordingly. In your app.js you can do this
import React, { Component } from "react";
import { BrowserRouter, Route } from "react-router-dom";
import Header from "./components/Header";
import DashBoard from "./components/Dashboard";
import Home from "./components/Home";
class App extends Component {
constructor() {
super();
this.state = {
isLoggedIn: localStorage.getItem("isloggedIn") || false,
};
}
onEventClick = () => {
const isLogged = localStorage.setItem("isloggedIn", true);
if (this.state.isLoggedIn === false) {
this.setState({ isLoggedIn: true });
} else {
localStorage.removeItem("isloggedIn");
this.setState({ isLoggedIn: false });
}
};
render() {
return (
<BrowserRouter>
<div className="container">
<Header
onEventClick={this.onEventClick}
LoggedInState={this.state.isLoggedIn}
/>
<Route path="/" exact={true} component={Home} />
<Route path="/dashboard" exact={true} component={DashBoard} />
</div>
</BrowserRouter>
);
}
}
export default App;
Related
I have some user components on which I used the navigation component and I am routing two components on it. when I click on the Device.js component button it should remove device.js and it should redirect to the Keyregister.js component which is having navigation component in it .It should change the value according to the props sent to it. But it is not happening.
user.js
import React from "react";
import { Route, Switch } from "react-router";
import "./User.css";
import Navigation from "./Dashboard/Navigation";
import AuthModel from "./Dashboard/AuthModel";
import DeviceDetails from "./Dashboard/DeviceDetails";
function User() {
return (
<>
<Navigation
link1={""}
link2={"Authmodel"}
link3={"Requests"}
link1name={"Key Status"}
link2name={"Key Upload"}
link3name={"KEY DOWNLOAD"}
/>
<Switch>
<Route path="/User/Dashboard/AuthModel" component={AuthModel} />
<Route path="/User/Dashboard/DeviceDetails" component={DeviceDetails} />
</Switch>
</>
);
}
export default User;
Navigation.js
import React from "react";
import "./Navigation.css";
import { Link } from "react-router-dom";
import { useHistory } from "react-router";
import { Image } from "react-bootstrap";
import EvoVert from "../../../Resources/EvoluteVert.png";
function Navigation(props) {
const history = useHistory();
const handleLogout = (e) => {
e.preventDefault();
localStorage.removeItem("accessToken");
localStorage.removeItem("roleType");
history.push("/");
};
return (
<>
<main classMain="main">
<aside className="sidebar ">
<Image className="Evo-logo" src={EvoVert} />
<nav className="nav">
<ul style={{ textDecoration: "none" }}>
<li>
<Link to={`/User/Dashboard/${props.link2}`}>
{props.link2name}
</Link>
</li>
<li>
<Link to={`/User/Dashboard/${props.link1}`}>
{props.link1name}
</Link>
</li>
<li>
<Link to={`/User/Dashboard/${props.link3}`}>
{props.link3name}
</Link>
</li>
</ul>
</nav>
</aside>
</main>
</>
);
}
export default Navigation;
Device.js
import React, { useState, useEffect } from "react";
import { Form } from "react-bootstrap";
import "./Dashboard.css";
import { useHistory } from "react-router";
import KeyRegister from "./KeyRegister";
function DeviceDetails() {
const history = useHistory();
const [visible, setvisible] = useState(true);
const [serialNum, setSerialNum] = useState("");
const [slot, setSlot] = useState("");
const frmsubmit = (e) => {};
return (
<>
<section className="device-Details_Dashboard">
<div className="container">
<div
className="heading"
style={{
color: "#312450",
fontWeight: "400",
fontSize: "35px",
padding: "1rem",
}}
>
DEVICE DETAILS
</div>
<Form onSubmit={frmsubmit}>
<div>
<div className="device-details-box">
<label>Serial Number</label>
<br />
<input
type="text"
value={serialNum}
onChange={(e) => setSerialNum(e.target.value)}
/>
</div>
<div className="device-details-box">
<label>Slot Number</label>
<br />
<input
type="text"
value={slot}
onChange={(e) => setSlot(e.target.value)}
/>
</div>
</div>
<button className="devDetSub" onClick={frmsubmit}>
<span>SUBMIT</span>
</button>
</Form>
</div>
</section>
{visible && <KeyRegister />}
</>
);
}
export default DeviceDetails;
KeyRegister.js
import React, { useState, useEffect } from "react";
import "./Navigation.css";
import { Route, Switch } from "react-router";
import DUPKT from "./DUPKT";
import MasterSession from "./MasterSession";
import AES from "./AES";
import Navigation from "./Navigation";
function KeyRegister() {
return (
<>
<Navigation
link1={"DUPKT"}
link2={"MasterSession"}
link3={"AES"}
link1name={"DUPKT"}
link2name={"MASTER KEY"}
link3name={"AES"}
/>
<main classMain="main">
<Switch>
<Route path="/User/Dashboard/DUPKT" component={DUPKT} exact />
<Route
path="/User/Dashboard/MasterSession"
component={MasterSession}
exact
/>
<Route path="/User/Dashboard/AES" component={AES} exact />
</Switch>
</main>
</>
);
}
export default KeyRegister;
I cannot see anywhere in your naviagation component props you are passing device details.
<Navigation
link1={""}
link2={"Authmodel"}
link3={"Requests"}
link1name={"Key Status"}
link2name={"Key Upload"}
link3name={"KEY DOWNLOAD"} //should have device details in props
/>
Hi I am pretty new to ReactJS, I am trying to move to the login page when Logout is clicked, the function is getting executed but it wont redirect to the login page. I don't know how to do it. I have tried using this.props.history.push but that is also not working. I have also tried using Redirect to="/login" in the fakeAuth.signout function.
import React, { Component } from 'react';
import './App.css';
import GetTodo from './component/getTodo.js';
import AddTodo from './component/addTodo.js';
import Login from './component/login.js';
import {BrowserRouter as Router,Switch,Route,Link,Redirect} from
'react-router-dom';
export const fakeAuth = {
isAuthenticated: false,
authenticate(cb) {
this.isAuthenticated = true;
},
signout(cb) {
this.isAuthenticated = false;
}
}
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={(props) => (
fakeAuth.isAuthenticated === true
? <Component {...props} />
: <Redirect to='/login' />
)} />
)
class App extends Component {
constructor(props){
super(props);
this.newsignout=this.newsignout.bind(this);
}
newsignout(){
fakeAuth.signout();
localStorage.clear();
<Redirect to="/login" />
}
render() {
return (
<Router>
<div className='App'>
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<div className="collapse navbar-collapse">
<div className="navbar-nav">
<div className="nav-item nav-link"><Link to={'/'}>GET TODO LIST</Link></div>
<div className="nav-item nav-link"><Link to={'/add'}>ADD TODO</Link></div>
<div className="nav-item nav-link"><Link to={'/login'}>LOGIN</Link></div>
<div className="nav-item nav-link "><div className="LogOut" onClick={()=>this.newsignout()}>LOGOUT</div></div>
</div>
</div>
</nav>
<Switch>
<PrivateRoute exact path='/' component={GetTodo} />
<PrivateRoute path='/add/:id' component={AddTodo} />
<PrivateRoute exact path='/add' component={AddTodo} />
<Route path='/login' component={Login}/>
</Switch>
</div>
</Router>
);
}
}
export default App;
You can use "State" and chang this page without Redirect.
For example:
class MyComponent extends React.Component {
constructor(){
super();
state = {
isLogin: true
}
}
newsignout(){
this.setState({ isLogin: false });
}
render () {
const { isLogin } = this.state;
if (!isLogin) {
return <LoginPage />; // for example
}
return <RenderYourForm/>; // other code
}
this is working
<div className="nav-item nav-link "><Link to={'/login'} className="LogOut" onClick={()=>this.newsignout()}>LOGOUT</Link></div>
I have this parent Component that simply renders a 'p' of the introduction text and a child component called 'PortfolioMenu'
import React from 'react'
import PortfolioMenu from './PortfolioMenu'
const Portfolio = () => {
return (
<div className="wrapper2">
<p>
Here is an Introduction text
</p>
<PortfolioMenu/>
</div>
)
}
export default Portfolio
Now in the child component 'PortfolioMenu', when I click on some link of NavLink I would like to make the 'p' of the parent component 'Portfolio' disappear. How can I solve it? Thank you
import React from 'react'
import { BrowserRouter as Router, Route, NavLink } from 'react-router-dom'
import Houses from './Houses'
import Interiors from './Interiors'
const PortfolioMenu = () => {
return (
<div>
<Router>
<div class="wrapper2">
<div className="wrapper-portfolio">
<Route exact path='/portfolio/houses' render={() => <Houses />} />
<Route exact path='/portfolio/interiors' render={() =><Interiors/>}
/>
</div>
<nav>
<ul className="portfolio-menu">
<li><NavLink activeClassName="active" exact
to="/portfolio/houses">Houses</NavLink></li>
<li><NavLink activeClassName="active" exact
to="/portfolio/interiors">interiors</NavLink></li>
</ul>
</nav>
</div>
</Router>
</div>
)
}
export default PortfolioMenu
Here you go with a solution
import React from 'react'
import PortfolioMenu from './PortfolioMenu'
const Portfolio = () => {
constructor(props) {
super(props){
this.state = {
visibleP: true
};
}
this.handleMenuClick = this.handleMenuClick.bind(this);
}
handleMenuClick() {
this.setState({
visibleP: false
});
}
return (
<div className="wrapper2">
{
this.visibleP &&
<p>
Here is an Introduction text
</p>
}
<PortfolioMenu onHandleMenuClick={this.handleMenuClick}/>
</div>
)
}
import React from 'react'
import { BrowserRouter as Router, Route, NavLink } from 'react-router-dom'
import Houses from './Houses'
import Interiors from './Interiors'
const PortfolioMenu = () => {
return (
<div>
<Router>
<div class="wrapper2">
<div className="wrapper-portfolio">
<Route exact path='/portfolio/houses' render={() => <Houses />} />
<Route exact path='/portfolio/interiors' render={() =><Interiors/>}
/>
</div>
<nav>
<ul className="portfolio-menu">
<li>
<NavLink
activeClassName="active"
exact
to="/portfolio/casas"
onClick={this.props.onHandleMenuClick()}
>
casas
</NavLink>
</li>
<li>
<NavLink
activeClassName="active"
exact
to="/portfolio/interiores"
onClick={this.props.onHandleMenuClick()}
>
interiores
</NavLink>
</li>
</ul>
</nav>
</div>
</Router>
</div>
)
}
PortfolioMenu.propTypes = {
onHandleMenuClick: PropTypes.func
};
export default PortfolioMenu;
You can't have a dump component. Here you need to pass props from child component to parent component.
I have a simple app with a home screen, a blog master list, and then blog detail page. Navigating from the home screen to the blog list and back works as expected. When I click on one of the blog posts the app navigates to the page and renders the blog post. But when I go back to the blog master list the blog post is now at the very bottom of the blog list. And if I then navigate back to the home page the same thing, the blog post is in the DOM behind the home page graphic.
I'm using react router 4.1.
Does it have to do with my route setup?
import React, { Component } from 'react'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import NavBar from './components/NavBar'
import Blog from './pages/blog'
import Home from './pages/home'
import Post from './pages/post'
import './css/App.css'
class App extends Component {
render() {
return (
<Router>
<div className="App">
<NavBar />
<Route exact path='/' component={Home} />
<Route path='/blog' component={Blog} />
<Route path='/post/:slug' component={Post} />
</div>
</Router>
)
}
}
export default App
Or with my post component?
import React from 'react'
import fetch from 'isomorphic-unfetch'
import NavBar from '../components/NavBar'
import dateUtils from '../utilities/DateAndTime'
const classNames = require('classnames')
class Post extends React.Component {
constructor(props) {
super(props)
this.state = {
blogObject: null,
fetchBlogObject: false
}
this.fetchBlogObject = this.fetchBlogObject.bind(this)
this.createMarkup = this.createMarkup.bind(this)
this.assignStyleToCoverImage = this.assignStyleToCoverImage.bind(this)
this.formatDateString = this.formatDateString.bind(this)
}
componentWillMount() {
this.fetchBlogObject()
}
componentWillReceiveProps() {
this.fetchBlogObject()
}
fetchBlogObject() {
console.log('fetching')
this.setState({ fetchBlogObject: true })
fetch(`*******************`)
.then(response => response.json())
.then((responseJson) => {
console.log(responseJson)
this.setState({ blogObject: responseJson.object })
})
}
createMarkup(stringToConvertToHtml) {
return { __html: stringToConvertToHtml }
}
assignStyleToCoverImage() {
const style = {
background: `url(${this.state.blogObject.metadata.hero.url})`,
height: '35vh',
backgroundSize: 'cover',
backgroundPosition: 'center'
}
return style
}
formatDateString(dateString) {
console.log(dateString)
const d = `${dateUtils.returnMonthFromISODateString(dateString)} ${dateUtils.returnDateNumberFromISOString(dateString)}, ${dateUtils.returnFullYearFromISOString(dateString)} by Phil Andrews`
return d
}
render() {
const postContainerClasses = classNames({
'post-container': true
})
const postBodyClasses = classNames({
'post-body': true
})
return (
<div>
<NavBar />
{this.state.blogObject ?
<div className={postContainerClasses} >
<div className='header-image' style={this.assignStyleToCoverImage(this.state.blogObject)} />
<div className='post-body-padding'>
<div className='post-header-info'>
<h1 className='post-title'>{this.state.blogObject.title}</h1>
<h4 className='post-date'>{this.formatDateString(this.state.blogObject.created_at)}</h4>
</div>
<div className={postBodyClasses} dangerouslySetInnerHTML={this.createMarkup(this.state.blogObject.content)} />
</div>
</div>
: <div>Loading...</div>
}
</div>
)
}
}
export default Post
Or with my blog list button action for navigating to a post page?
<Link id={this.props.blogObject.slug} to={`/post/${this.props.blogObject.slug}`}>
<button className='blog-button' style={buttonStyle} id={this.props.blogObject.slug} />
</Link>
I'm not sure why it would continue to render the entire component but if I get rid of the <NavBar /> in the post component the issue goes away.
Not working:
return (
<div>
<NavBar />
{this.state.blogObject ?
<div className={postContainerClasses} >
<div className='header-image' style={this.assignStyleToCoverImage(this.state.blogObject)} />
<div className='post-body-padding'>
<div className='post-header-info'>
<h1 className='post-title'>{this.state.blogObject.title}</h1>
<h4 className='post-date'>{this.formatDateString(this.state.blogObject.created_at)}</h4>
</div>
<div className={postBodyClasses} dangerouslySetInnerHTML={this.createMarkup(this.state.blogObject.content)} />
</div>
</div>
: <div>Loading...</div>
}
</div>
)
Working:
return (
<div>
{this.state.blogObject ?
<div className={postContainerClasses} >
<div className='header-image' style={this.assignStyleToCoverImage(this.state.blogObject)} />
<div className='post-body-padding'>
<div className='post-header-info'>
<h1 className='post-title'>{this.state.blogObject.title}</h1>
<h4 className='post-date'>{this.formatDateString(this.state.blogObject.created_at)}</h4>
</div>
<div className={postBodyClasses} dangerouslySetInnerHTML={this.createMarkup(this.state.blogObject.content)} />
</div>
</div>
: <div>Loading...</div>
}
</div>
)
I have a repo at https://bitbucket.org/codyc54321/anthony-project-react
I have the homepage showing links, and when you click the links react-router works. But the text of the component is not showing up, like <div>Login page</div>, <div>Homepage</div>, etc.
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Link, IndexRoute, browserHistory } from 'react-router';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import reducers from './reducers';
import Nav from './Nav';
import Home from './components/Home';
import Login from './components/Login';
import SignupMain from './components/SignupMain';
const createStoreWithMiddleware = applyMiddleware()(createStore);
ReactDOM.render(
(
<Provider store={createStoreWithMiddleware(reducers)}>
<Router history={browserHistory}>
<Route path="/" component={Nav}>
<IndexRoute component={Home}/>
<Route path='/login' component={Login}/>
<Route path='/signup-main' component={SignupMain}/>
</Route>
</Router>
</Provider>
), document.querySelector('.container'));
Nav.js:
import React from 'react';
import { Link } from 'react-router';
export default class Nav extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<nav className="navbar navbar-default">
<div className="container-fluid">
<div className="navbar-header navbar-brand">
Home
</div>
</div>
<div id="navbar" className="navbar-right">
<ul className="nav navbar-nav">
<li><Link activeClassName="active" to="/" onlyActiveOnIndex>Home</Link></li>
<li><Link activeClassName="active" to="/login" onlyActiveOnIndex>Login</Link></li>
<li><Link activeClassName="active" to="/signup-main" onlyActiveOnIndex>Signup</Link></li>
</ul>
</div>
</nav>
</div>
)
}
}
// export Nav as default;
components/Home.js:
import React, { Component } from 'react';
export default class Home extends Component {
render() {
return (
<div>Homepage</div>
);
}
}
Why aren't these components showing up on the page?
Since your other routes are nested inside the route for 'Nav' component, it should render its children somewhere. For that, you have to put this.props.children where you want to render nested components in JSX of Nav component.
export default class Nav extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<nav className="navbar navbar-default">
<div className="container-fluid">
<div className="navbar-header navbar-brand">
Home
</div>
</div>
<div id="navbar" className="navbar-right">
<ul className="nav navbar-nav">
<li><Link activeClassName="active" to="/" onlyActiveOnIndex>Home</Link></li>
<li><Link activeClassName="active" to="/login" onlyActiveOnIndex>Login</Link></li>
<li><Link activeClassName="active" to="/signup-main" onlyActiveOnIndex>Signup</Link></li>
</ul>
</div>
</nav>
<div>{this.props.children}</div>
</div>
)
}
}