I am trying to change the navigation bar contents from Sign In/Register to other things such as Profile once the user logs in. My server sends a 401 when the user is not logged in and I have a HOC (RequireAuth.js) which checks the same for protected routes and redirects them to login if they have not logged in. However, I could not come up with a way to change the navbar contents with this logic and was wondering if there is a good way to do this (I do not want to use Redux for this purpose if possible).
RequireAuth.js
const RequireAuth = ( Component ) => {
return class Apps extends React.Component {
state = {
isAuthenticated: false,
isLoading: true
}
checkAuthentication = async() => {
const url = '/getinfo'
const json = await fetch(url, {method: 'GET'})
if (json.status !== 401) {
setTimeout(
function() {
this.setState({isAuthenticated: true, isLoading: false});}.bind(this), 1500);
} else {
setTimeout(
function() {
this.setState({isLoading: false});}.bind(this), 1500);
}
}
componentDidMount() {
this.checkAuthentication()
}
render() {
const style = {position: "fixed", top: "50%", left: "50%", transform: "translate(-50%, -50%)" };
console.log(this.state.isLoading)
const { isAuthenticated, isLoading } = this.state;
if(!isAuthenticated) {
return this.state.isLoading? <div style={style}><PacmanLoader color={'#36D7CC'}/></div> : <Redirect to="/" />
}
return <Component {...this.props} />
}
}
}
export { RequireAuth }
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
const NotFoundComponent = () => <div>404 NOT FOUND</div>
return (
<div>
<Router>
<NavigationBar />
<Switch>
<Route exact path = '/'
component = {LandingPage}
/>
<Route exact path = '/register'
component = {Register}
/>
<Route exact path = '/Profile'
component = {RequireAuth(Profile)}
/>
<Route exact path = '/About'
component = {RequireAuth(About)}
/>
<Route exact path = '/Name'
component = {RequireAuth(Name)}
/>
<Route path="*" component = {NotFoundComponent}/>
</Switch>
</Router>
</div>
);
}
}
export default withRouter(App);
Navigation.js
class NavigationBar extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<Navbar bg="dark" variant="dark" expand="lg">
<Navbar.Brand >Hello</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="ml-auto">
<Nav.Link as={Link} to='/'>Login</Nav.Link>
<Nav.Link as={Link} to='/register'>Register</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
)
}
}
export default withRouter(NavigationBar);
Related
I am having a navbar and a side bar for my page.
Navbar consists of home and blogs
Blogs will render BlogHome Component which will fetch links from db and on click of any link will render BlogContent component.
Lets say the side bar has Blog1,Blog2 and Blog3 listed. If I click Blog1 it renders Blog1's content properly to its side, but if I click Blog2 again it just changes URL but not the Blog2's content.
Please take a look at my code:
Navbar.js
<Router>
<Container className="p-0" fluid={true}>
<Navbar className="border-bottom" bg="transparent" expand="lg">
<Navbar.Brand>{global.config.appname}</Navbar.Brand>
<Navbar.Toggle className="border-0" aria-controls="navbar-toggle" />
<Navbar.Collapse id="navbar-toggle">
<Nav className="ml-auto">
<Link className="nav-link" to="/">Home</Link>
<Link className="nav-link" to="/blogs/main">Blogs</Link>
<Link className="nav-link" to="/contact">Contact</Link>
</Nav>
</Navbar.Collapse>
</Navbar>
</Container>
<Switch>
<Route exact path="/" component={Home}></Route>
<Route exact path="/blogs/main" component={BlogHome}></Route>
</Switch>
</Router>
BlogHome.js
export default class BlogHome extends Component {
constructor(props)
{
super(props);
this.state = { data: null,route:null };
}
componentDidMount = () => {
console.log("BlogHome");
BlogDataService.getAll().then(data => {
let data_temp = []
let cnt = 0;
for (let item of data.data) {
data_temp.push(
<MenuItem key={cnt++} icon={<FaBlog />}>
<Link to={"/blogs/main/" + item.id}>{item.title}</Link>
</MenuItem>
);
}
this.setState({ data: data_temp });
})
}
render() {
return (
<Router>
<div style={{ display: "flex" }}>
<ProSidebar>
<Menu iconShape="square">
{this.state.data}
</Menu>
</ProSidebar>
<Switch>
<Route exact path={"/blogs/main/:blogId"} component={BlogContent}></Route>
</Switch>
</div>
</Router>
);
}
}
BlogContent.js
export default class BlogContent extends Component {
constructor(props) {
super(props);
const contentState = convertFromRaw(content);
this.state = {
contentState,
item_id: this.props.match.params.blogId,
title:null
}
console.log(this.props.match);
}
onContentStateChange: function = (contentState) => {
this.setState({
contentState,
});
};
componentDidMount = () => {
BlogDataService.get(this.state.item_id).then(data => {
console.log(data);
this.setState({ title: data.data.title })
});
}
render() {
const { contentState } = this.state;
return (
<Router>
<div style={{padding:"10px"}}>
<div style={{padding:"50px",fontSize:"50px"}}>
{this.state.title}
</div>
<Editor
wrapperClassName="demo-wrapper"
editorClassName="demo-editor"
onContentStateChange={this.onContentStateChange}
/>
<Route exact path={"/blogs/main/1"} component={BlogContent}></Route>
</div>
</Router>
);
}
}
Thank you for reading :)
your item_id is set only one time and it is not changing at all. On first time when component load it will work but when you are doing second time you are passing new item id but component is not aware about this change hence not able to do anything.
Try to create a function which fetch data. Same function call it in componentDidmount.
Now when it is getting new props it is time to check . Use componentDidUpdate.
componentDidUpdate(prevProps, prevState){
if(prevProps.blogId != this.props.blogId){
this.setState({
item_id: this.props.blogId
}, () => { call the function to get the data } )
}
}
I just tried to build the react-router docs ex on browser but there is problem in AuthButton component it isn't showing signOut button when the isAuthenticated turns true
import React from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
Redirect,
useHistory,
useLocation,
} from 'react-router-dom';
export default function AuthExample() {
return (
<Router>
<div>
<AuthButton />
<ul>
<li>
<Link to='/public'>Public Page</Link>
</li>
<li>
<Link to='/protected'>Protected Page</Link>
</li>
</ul>
<Switch>
<Route path='/public'>
<PublicPage />
</Route>
<Route path='/login'>
<LoginPage />
</Route>
<PrivateRoute path='/protected'>
<ProtectedPage />
</PrivateRoute>
</Switch>
</div>
</Router>
);
}
const fakeAuth = {
isAuthenticated: false,
authenticate(cb) {
fakeAuth.isAuthenticated = true;
setTimeout(cb, 100); // fake async
},
signout(cb) {
fakeAuth.isAuthenticated = false;
setTimeout(cb, 100);
},
};
function AuthButton() {
let history = useHistory();
return fakeAuth.isAuthenticated ? (
<p>
Welcome!{' '}
<button
onClick={() => {
fakeAuth.signout(() => history.push('/'));
}}>
Sign out
</button>
</p>
) : (
<p>You are not logged in.</p>
);
}
function PrivateRoute({ children, ...rest }) {
return (
<Route
{...rest}
render={({ location }) =>
fakeAuth.isAuthenticated ? (
children
) : (
<Redirect
to={{
pathname: '/login',
state: { from: location },
}}
/>
)
}
/>
);
}
function PublicPage() {
return <h3>Public</h3>;
}
function ProtectedPage() {
return <h3>Protected</h3>;
}
function LoginPage() {
let history = useHistory();
let location = useLocation();
let { from } = location.state || { from: { pathname: '/' } };
let login = () => {
fakeAuth.authenticate(() => {
history.replace(from);
});
};
return (
<div>
<p>You must log in to view the page at {from.pathname}</p>
<button onClick={login}>Log in</button>
</div>
);
}
The reason it's not updating is because it doesn't know to update. You change the route but AuthButton doesn't know to re-render based on the route you need to pass it a prop so that it knows when to update. I refactored your code to incorporate using react hooks. By using hooks you can store isAuthenticated in local state in AuthExample via useState.
From AuthExample, pass down the state value for isAuthenticated as a prop to AuthButton. If the prop changes, AuthButton will detect it and this will trigger a re-render of AuthButton and reflect the correct component structure you are looking for. See below.
import React, { useState } from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
Redirect,
useHistory,
useLocation
} from "react-router-dom";
export default function AuthExample() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const fakeAuth = {
isAuthenticated: isAuthenticated,
authenticate(cb) {
fakeAuth.isAuthenticated = true;
setIsAuthenticated(true);
setTimeout(cb, 100); // fake async
},
signout(cb) {
setIsAuthenticated(false);
fakeAuth.isAuthenticated = false;
setTimeout(cb, 100);
}
};
return (
<Router>
<div>
<AuthButton fakeAuth={fakeAuth} isAuthenticated={isAuthenticated} />
<ul>
<li>
<Link to="/public">Public Page</Link>
</li>
<li>
<Link to="/protected">Protected Page</Link>
</li>
</ul>
<Switch>
<Route path="/public">
<PublicPage />
</Route>
<Route path="/login">
<LoginPage fakeAuth={fakeAuth} />
</Route>
<PrivateRoute path="/protected" fakeAuth={fakeAuth}>
<ProtectedPage />
</PrivateRoute>
</Switch>
</div>
</Router>
);
}
function AuthButton(props) {
const { fakeAuth, isAuthenticated } = props;
let history = useHistory();
return isAuthenticated ? (
<p>
Welcome!{" "}
<button
onClick={() => {
fakeAuth.signout(() => history.push("/"));
}}
>
Sign out
</button>
</p>
) : (
<p>You are not logged in.</p>
);
}
function PrivateRoute({ children, ...rest }) {
const { fakeAuth } = rest;
return (
<Route
{...rest}
render={({ location }) =>
fakeAuth.isAuthenticated ? (
children
) : (
<Redirect
to={{
pathname: "/login",
state: { from: location }
}}
/>
)
}
/>
);
}
function PublicPage() {
return <h3>Public</h3>;
}
function ProtectedPage() {
return <h3>Protected</h3>;
}
function LoginPage(props) {
const { fakeAuth } = props;
let history = useHistory();
let location = useLocation();
let { from } = location.state || { from: { pathname: "/" } };
let login = () => {
fakeAuth.authenticate(() => {
history.replace(from);
});
};
return (
<div>
<p>You must log in to view the page at {from.pathname}</p>
<button onClick={login}>Log in</button>
</div>
);
}
You can also see a working example in this code sandbox. There are a few ways to do this but hooks make it easy to manipulate state values to update functional components without having to make them class components. This way also keeps most of your code intact as is just adding a few checks for when isAuthenticated is updated.
I think the problem is in rendering process.
In my opinion, if you put the sub-functions in to the exported function, this problem may solve.
If the problem won't solve, try the class base component for handling this rendering process.
wish you success
I am building an Higher Order component to create a Idle Timeout featuer in my react app. I have the autologout component, I am in the process of including that in my index.js file. I am however, running into an issue where its unable to read the path. What am i doing wrong?
Here is my HOC component:
import IdleTimer from "react-idle-timer";
import React, { Component } from 'react'
import PropTypes from 'prop-types';
import { Switch, Route } from 'react-router-dom'
import DefaultLayout from "../containers/DefaultLayout";
export default function HOC (WrappedComponent) {
return class extends Component{
constructor(props) {
super(props);
this.state = {
timeout: 1000*5,
showModal: false,
userLoggedIn: false,
isTimedOut: false
};
this.idleTimer = null;
this.onAction = this._onAction.bind(this);
this.onActive = this._onActive.bind(this);
this.onIdle = this._onIdle.bind(this);
}
_onAction(e){
console.log('User did something', e);
this.setState({isTimedOut: false})
}
_onActive(e){
console.log('user is active', e);
this.setState({isTimedOut: false})
}
_onIdle(e){
console.log('user is idle', e);
const isTimedOut = this.state.isTimedOut;
if (isTimedOut){
this.props.history.push('/')
}else {
this.setState({showModal: true});
this.idleTimer.reset();
this.setState({isTimedOut: true})
}
}
render() {
const { match } = this.props;
return (
<WrappedComponent>
<IdleTimer
ref={ref => {this.idleTimer = ref}}
element={document}
onActive={this.onActive}
onIdle={this.onIdle}
onAction={this.onAction}
debounce={250}
timeout={this.state.timeout} />
<div className="">
<Switch>
<Route
exact path={`${match.path}/sales-analysis/dashboard`}
render={(props) => <DefaultLayout {...props} /> }/>
/>
</Switch>
</div>
</WrappedComponent>
)
}
}
}
HOC.propTypes = {
match: PropTypes.any.isRequired,
history: PropTypes.func.isRequired
};
Here is the index.js file containing the routes I am tyring to monitor
class AppEntry extends React.Component {
componentDidMount() {
window.addEventListener("appNotifyUpdate", this.appNotifyUpdate);
window.addEventListener("appUpdate", this.appUpdate);
window.addEventListener("offline", function(e) {
store.dispatch(setOffline(true));
});
window.addEventListener("online", function(e) {
store.dispatch(setOffline(false));
});
}
componentWillUnmount() {
window.removeEventListener("appNotifyUpdate", this.appNotifyUpdate);
window.removeEventListener("appUpdate", this.appUpdate);
window.removeEventListener("offline", function(e) {
store.dispatch(setOffline(true));
});
window.removeEventListener("online", function(e) {
store.dispatch(setOffline(false));
});
}
appNotifyUpdate = e => {
store.dispatch(setAppUpdateBar(true));
};
appUpdate = e => {
store.dispatch(setAppUpdateBar(false));
};
render() {
return (
<Provider store={this.props.store}>
<PersistGate loading={<div />} persistor={this.props.persistor}>
<BrowserRouter>
<div id="browserRouter">
<Route exact path="/" component={LoginContainer} key="login" />
<Route
path="/change-password"
component={LoginContainer}
key="change-password"
/>
<Route path="/logout" component={Logout} key="logout" />
<DefaultLayout
path="/sales-analysis/dashboard"
component={HOC(DashboardContainer)}
/>
<DefaultLayout
path="/sales-analysis/active-clients"
component={ActiveClientsContainer}
/>
<DefaultLayout
path="/sales-analysis/activity-reports"
component={ActivityReportsContainer}
/>
<DefaultLayout
path="/sales-analysis/segments"
component={SegmentsContainer}
/>
<DefaultLayout path="/prospects" component={ProspectsContainer} />
<DefaultLayout
path="/preferences/general"
component={PreferenceGeneral}
/>
<DefaultLayout
path="/preferences/account-manager"
component={PreferenceAccountManager}
/>
<DefaultLayout
path="/preferences/flex-fields"
component={PreferenceFlexFields}
/>
<DefaultLayout
path="/preferences/oem-manager"
component={PreferenceOEMManager}
/>
<DefaultLayout
path="/preferences/users"
component={PreferenceUsers}
/>
<DefaultLayout
path="/preferences/group-users"
component={PreferenceGroupUsers}
/>
</div>
</BrowserRouter>
</PersistGate>
</Provider>
);
}
}
AppEntry = HOC(AppEntry);
The exact error I am getting is this
TypeError: Cannot read property 'path' of undefined
render
./src/components/AutoLogout.js:65:52
62 | <div className="">
63 | <Switch>
64 | <Route
> 65 | exact path={`${match.path}/sales-analysis/dashboard`}
| render={(props) => <DefaultLayout {...props} /> }/>
67 | />
68 | </Switch>
This is due the fact you are not passing down props to your HoC.
Try, (Eg):
//Imports
import HOC from 'path/to/my/hoc';
//...code
const MyHoc = HOC(DashboardContainer);
//Main class
class AppEntry extends React.Component {
//...code
// In the render method take advantage of render prop
render() {
return (
//...code
<Route exact path="/my-path" render={(props) => <MyHoc {...props} />} />
I am developing a Reactjs web application from scratch and encountered a tricky situation which i need help with. Whenever i navigate away from a particular url and navigate back, my redux store does not seem to be connected.
routes.js
const RouteList = () => (
<main>
<Switch>
<Route path="/abc/" exact component={withRouter(HomePage)} />
<Route path="/abc/xyz" exact component={withRouter(XYZPage)} />
<Redirect from="/" to="/abc/" />
<Route component={Error} />
</Switch>
</main>
);
export default RouteList;
App.js
class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render () {
return (
<Router history={browserHistory}>
<div>
<Header />
<RouteList />
<Footer />
</div>
</Router>
);
}
}
export default App;
Header.js
const Header = () => {
return (
<Navbar expand="md">
<NavbarBrand tag={NavLink} to="/">
<img src={brandImage} style={{marginRight: "0", width: "40px", height: "40px"}} /><strong style={{color: "#457B9D"}} >Datum</strong>
</NavbarBrand>
<Nav className="mr-auto" navbar>
<NavItem>
<NavLink className="nav-link" to={"/abc/xyz"} >XYZ</NavLink>
</NavItem>
</Nav>
</Navbar>
);
};
export default withRouter(Header);
When i hit the NavLink which will take me to url: /"abc/xyz", it will take me to XYZPage.js
XYZPage.js
class XYZPage extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
activeTab: "1"
};
this.toggle = this.toggle.bind(this);
}
toggle(tab) {
if (this.state.activeTab !== tab) {
this.setState({
activeTab: tab
});
}
}
render () {
return (
<main>
<div className="container-fluid pt-3">
<Nav tabs>
<NavItem>
<NavLink
className={classnames({active: this.state.activeTab === "1"})}
onClick={() => {this.toggle("1"); }} >
AAA
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={classnames({active: this.state.activeTab === "2"})}
onClick={() => {this.toggle("2"); }} >
BBB
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={classnames({active: this.state.activeTab === "3"})}
onClick={() => {this.toggle("3"); }} >
CCC
</NavLink>
</NavItem>
</Nav>
<TabContent activeTab={this.state.activeTab}>
<TabPane tabId="1">
<Row>
<AAAPAge/>
</Row>
</TabPane>
<TabPane tabId="2">
<Row>
<BBBPage/>
</Row>
</TabPane>
<TabPane tabId="3">
<Row>
<CCCPage/>
</Row>
</TabPane>
</TabContent>
</div>
</main>
);
}
}
export default withRouter(XYZPage);
Each of the AAAPage, BBBPage & CCCPage are components which needs to have some pre-populated dropdowns which i declared in my index.js below:
index.js
const store = configureStore();
store.dispatch(loadAAA());
store.dispatch(loadBBB());
store.dispatch(loadCCC());
render((
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
), document.getElementById('app'));
loadAAA, loadBBB & loadCCC are all thunks
The configureStore() method is as such:
export default function configureStore(initialState) {
return createStore(
rootReducer,
initialState,
composeWithDevTools(
applyMiddleware(thunk, reduxImmutableStateInvariant()),
)
);
}
To shorten this post i give a sample of my AAAPage as the others are of similar structure:
AAAPage.js:
class AAAPage extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {...};
}
componentWillReceiveProps(nextProps) {...}
render() {
[...]
return (
<Container fluid>
<Row>
<AAAInputForm
// Data from Store is passed here
/>
</Row>
{ChildComponent}
</Container>
);
}
}
AAAPage.propTypes = {
DATA: PropTypes.array
};
function mapStateToProps(state, ownProps) {
let DATA = [];
if (state.AAAReducer.length > 0) {
DATA = state.AAAReducer;
}
return {
DATA: DATA
};
}
export default withRouter(connect(mapStateToProps)(AAAPage));
AAAReducer.js:
export default function AAAReducer(state=initialState.AAAList, action) {
switch(action.type) {
case types.LOAD_AAA_SUCCESS:
return action.AAAList;
default:
return state;
}
}
AAAAction.js:
export function loadAAASuccess(AAAList) {
return {
type: types.LOAD_AAA_SUCCESS,
AAAList: AAAlList
};
}
// thunk
export function loadAAA() {
// A thunk will always return a function that accepts a dispatch
return function(dispatch) {
return apiCall("ALL").then(response => {
dispatch(loadAAASuccess(response.data.AAA));
}).catch(error => {
throw(error);
});
};
}
initialState.js:
export default {
AAAList: [],
BBBList: [],
CCCList: []
};
At this point i believe i provided enough background to my code. I followed tutorials when designing this redux store and I am not sure why when i navigate from "/abc/xyz" to "/abc" and back, or when i navigate to "/abc/xyz" from "/abc", my stores are empty although i called the loadAAA() method at my index.js. All the other pages are affected as well. However, when i hit "/abc/xyz" directly, my stores are connected and my dropdowns are populated. What is happening? Is it because of my lifecycle methods?
I am using react v15.6.2, redux v3.7.2 & redux-thunk v2.3.0.
Thanks for the guidance.
You only call loadAAA at the top level of index.js, which only executes once when your page loads. If you want to dispatch it every time your XYZPage page renders, put in XYZ's componentDidMount
#AKJ - #Andy Ray said it correctly, but I'll like to add that componentDidMount is the best place to load async calls, as it is called after render and about Store redux store keeps data until you refresh the page after refresh redux store is reinitialized, if you need store the data after refresh try redux-persist
I am building an ad website. I built a registration system, which works perfectly fine, but for some reason I can't update the NavBar based on the event that has happened. For example, I want to replace the NavLink called "LOGIN/REGISTER" with "LOGGED IN". I have passed the props of the User.ID from the parent component (App.js) into the other components without any problem, but cannot do this for the NavBar. If I try a console.log - it would say undefined. I am going to put a couple of codes demonstrating where it works and where it does not:
APP.JS
*imports, which I am skipping*
const cookies = new Cookies();
class App extends Component {
constructor(){
super();
this.state = {
}
this.LogUser = this.LogUser.bind(this);
this.LogoutUser = this.LogoutUser.bind(this);
}
LogUser(User, ID){
cookies.set('User', User, { path: '/' });
cookies.set('UserID', ID,{ path: '/'});
}
LogoutUser(){
cookies.remove('User')
}
render() {
return (
<div>
<div>
//MENU <- WHERE I CAN'T PASS THE PROPS OF USER AND USERID
<Menu render={(props) => <Menu {...props} User={cookies.get('User')} ID={cookies.get('UserID')} LogOutUser={this.LogoutUser} />}/>
</div>
<Router history = {history} >
<div>
//I have removed all other routes as they are not needed, but here is an example, in which the passing of props works
<Route path = "/Profile" render={(props) => <Profile {...props} User={cookies.get('User')} ID={cookies.get('UserID')} LogOutUser={this.LogoutUser} />}/>
</div>
</Router>
</div>
);
}
}
export default App;
And for example in Profile.jsx, I can do that:
PROFILE.JSX
export default class Profile extends Component {
constructor(props, context) {
super(props, context);
this.state = {
LoggedUser: '',
UserID: '',
};
this.LogOutClick = this.LogOutClick.bind(this);
}
LogOutClick(){
this.props.LogOutUser();
history.push('/Logout');
}
componentDidMount(){
if (this.props.User !== undefined)
{
this.setState({LoggedUser: this.props.User, UserID: this.props.ID})
}
else
{
history.push('/Login');
}
}
render() {
return (
<div>
Hello, {this.props.User}!
<div>
)}}
But when I try it in the Menu component, I can't manage it to update accordingly:
NAVBAR.JSX
export default class Menu extends React.Component {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.state = {
isOpen: false,
Title: '',
};
}
toggle() {
this.setState({
isOpen: !this.state.isOpen
});
}
//here I tried to put something similar to the ComponentDidMount() in Profile.jsx, but it didn't work.
componentDidMount(){
if (this.props.User !== undefined)
{
this.setState({LoggedUser: this.props.User, UserID: this.props.ID})
this.setState({Title: "LOGGED IN"})
}
else
{
this.setState({Title: "LOGIN/REGISTER"})
}
}
render() {
console.log(this.state.User)
console.log(this.state.ID)
return (
<div>
<Navbar color="light" light expand="md">
<NavbarBrand href="/"><img src={require('./images/home.png')} width = "25px" height = "25px"/></NavbarBrand>
<NavbarToggler onClick={this.toggle} />
<Collapse isOpen={this.state.isOpen} navbar>
<Nav className="ml-auto1" navbar>
<NavItem>
<NavLink href="/Ads"><b>ADS</b></NavLink>
</NavItem>
<NavItem>
<NavLink href="/Profile"><b>YOUR PROFILE</b></NavLink>
</NavItem>
<NavItem>
//What I want to update
<NavLink href="/Login"><b>{this.state.Title}</b></NavLink>
</NavItem>
</Nav>
</Collapse>
</Navbar>
</div>
);
}
}
React will only update in response to a new state or new props. You are manipulating a cookie which can't cause a component re-render. Here's a solution:
In your App component change the Log methods to:
constructor(){
super();
this.state ={
currentUserId: cookies.get('UserID'),
currentUser: cookies.get('User')
};
this.LogUser = this.LogUser.bind(this);
this.LogoutUser = this.LogoutUser.bind(this);
}
LogUser(User, ID){
cookies.set('User', User, { path: '/' });
cookies.set('UserID', ID,{ path: '/'});
this.setState({
currentUserId: ID,
currentUser: User
});
}
LogoutUser(){
cookies.remove('User');
this.setState({
currentUserId: null,
currentUser: null
});
}
And your render will become:
render() {
return (
<div>
<div>
<Menu render={(props) => <Menu {...props} User={this.state.currentUser} ID={this.state.currentUserId} LogOutUser={this.LogoutUser} />}/>
</div>
<Router history = {history} >
<div>
//I have removed all other routes as they are not needed, but here is an example, in which the passing of props works
<Route path = "/Profile" render={(props) => <Profile {...props} User={this.state.currentUser} ID={this.state.currentUserId} LogOutUser={this.LogoutUser} />}/>
</div>
</Router>
</div>
);
}