Reputation: 341
I want the Navbar to change state but I couldn't figure out how to pass state from Login to Navbar without using Redux. It only updates the state of the Navbar after I manually refresh the page. This is not good. It would be great if once I click on the Login button, then the Navbar also updates its state. How can I pass the state over?
App component:
const App = () => {
return (
<BrowserRouter>
<div className="App">
<Navbar />
<Switch>
<Login exact path="/login" component={Login} />
<Signup exact path="/signup" component={Signup} />
</Switch>
</div>
</BrowserRouter>
);
};
Navbar component:
class Navbar extends React.Component {
constructor() {
super();
this.state = {
modalOpen: false,
isAuthenticated: false,
name: '',
};
}
componentDidMount() {
if (localStorage.getItem('token')) {
this.setState({ isAuthenticated: true });
}
}
render() {
return (
<div className="navbar">
<div className="navbar-flex">
{this.state.isAuthenticated && <p>Hello {this.state.name}</p>}
<Button onClick={this.toggleModal}>Menu</Button>
</div>
{this.state.modalOpen && (
<div className="modal" ref={this.setWrapperRef}>
{!this.state.isAuthenticated ? (
<div>
<Link to="/">
<Button onClick={() => this.setState({ modalOpen: false })}>Home</Button>
</Link>
<Link to="/login">
<Button onClick={() => this.setState({ modalOpen: false })}>Login</Button>
</Link>
<Link to="/signup">
<Button onClick={() => this.setState({ modalOpen: false })}>Signup</Button>
</Link>
</div>
) : (
<div>
<Link to="/">
<Button onClick={() => this.setState({ modalOpen: false })}>Home</Button>
</Link>
<Link to="/">
<Button onClick={this.logout}>Logout</Button>
</Link>
</div>
)}
</div>
)}
</div>
);
}
Login component submit method:
onSubmit = (e) => {
e.preventDefault();
this.setState({ loading: true });
axios
.post('/api/login', {
email: this.state.email,
password: this.state.password,
})
.then((res) => {
if (res.data.token) {
localStorage.setItem('token', res.data.token);
this.setState({ loading: false });
this.props.history.push('/');
} else if (res.data.status === 'fail') {
this.setState({ loading: false });
}
});
};
Upvotes: 2
Views: 959
Reputation: 133
You can put the isAuntheticated
state in the App.js container, and then pass the function to update it in Login, and it's state in NavBar.
Something like:
const App = () => {
const [unauthenticated, setIsAuthenticated] = useState(false);
return (
<BrowserRouter>
<div className="App">
<Navbar />
<Switch>
<Login exact path="/login" component={Login} isAuthenticated={isAuthenticated} />
<Signup exact path="/signup" component={Signup} setIsAuthenticated={setIsAuthenticated} />
</Switch>
</div>
</BrowserRouter>
);
};
And then in login, you can use setIsAunthenticated
to update the state along with updating the localstorage.
And then in NavBar in render, you can use !this.state.isAuthenticated || !this.props.isAuthenticated
to render your navigation.
Do note that this can work well in small applications, but for large projects you should always use global state like Redux. Or if you don't want to include any extra libraries, you can use ContextAPI, react's own implementation of global state.
Upvotes: 0
Reputation: 703
Here is how i control my navbars to reflect on the current state (Authenticated or not).
you can create a method that checks the local storage for the token and returns false or true as a result, or you can perform anything you want to do to ensure authentication and return the value based on that.
const isAuthenticated = (token) => {
localStorage.getItem(token) ? true:false;
}
and then you can import it and on componentDidMount()
you can call the method and store the result and do whatever you want to do with it.
Upvotes: 2