I am working on an application that uses React and Redux and I wanted to add a login page but I didn't have time initially to create a fully secure frontend login. So, as a placeholder I used localStorage to keep track of who was logged in. Let me show you how I did it.
First: Look at your REDUX Store
After someone logs into my site I add the user to my Redux Store:
...state
user: { id: //user's ID from the database
username: //name the user chose to login with
...other_data //other data I associated with a user
}
This works easily enough. As long as the state exists in the Redux store I can see who is logged in. The only issue is if someone refreshes or types a URL directly. If that happens the store has to be re-generated and the user appears to not be logged in.
Second: Set up props on a component
So, I just had to use some lifecycle methods with localStorage.
I can't use componentDidMount() initially because when you first come to the application the user has not logged in. So when the component mounts there won't be any user data. So instead I looked to componentDidUpdate().
To make this work I had to insure that I had the user.id in props. This way when the user logged in, the user.id would change and therefore the props would change. Then this component would update allowing my componentDidUpdate() to trigger.
function mapStateToProps(state) {
return {user: {id: state.user.id}}
}
Note that I only retrieved the user's ID and not the entire user object from the store's state. This is because I have other data stored as an array within the user object and that data can change pretty frequently. I don't want this page to need to re-render whenever a user's data changes. I only want to re-render when the user object changes completely.
This might sound obvious, but it tripped me up for a while because I didn't consider what would trigger this page to re-render.
Third: Use Lifecycle Methods and localStorage
So now that I have the correct props coming in I can set up my componentDidUpdate() method.
componentDidUpdate(prevProps) {
localStorage.setItem('userID', this.props.user.id);
}
}
Pretty straight forward here. When this page re-renders it grabs the ID from the props and sets it in localStorage. That first argument is basically a variable name and the second is the value. I called it 'userID' but you can name it whatever you want.
What this doesn't account for is if someone logs out. I also need to clear the localStorage when someone logs out. I could have cleared localStorage in the reducer or on the page where a user chooses to log out but I wanted to have all my localStorage accessing in one place. So I added a little bit of logic to this componentDidUpdate() method.
componentDidUpdate(prevProps) {
let storedID = localStorage.getItem('userID');
if (this.props.user.id && this.props.user.id !== storedID ) {
localStorage.setItem('userID', this.props.user.id);
}
}
Now I first check localStorage and grab the userID that is stored there. If I am coming to the application for the first time this won't find any data. That's ok. This method shouldn't run anyway since it will only run when the user.id in props changes. If you've logged out, it will find the old userID here. (Did you know: the same userID should be stored in prevProps as well!)
Now for that little bit of logic. If there is now a user.id in the props and that user.id is different from the what's already in the localStorage set the localStorage with the new user.id. If you are logging out it will set this localStorage to a blank string.
Finally: Let's deal with Users who Refresh the page!
One last thing to worry about, and truly the only reason I am using localStorage. What if someone refreshes the page or types a URL directly instead of using my easy links? (Why is this someone not trusting the simplicity of this SPA?)
This is where componentDidMount() comes into play. When this page is mounted for the first time I need to do a little checking.
componentDidMount() {
let userID = localStorage.getItem('userID');
if (userID) {
this.props.findUser(userID)
}
}
Once again I tell my component to check localStorage for a userID. If a user is already logged in it will find that stored userID. So then I just call a method (that I defined earlier with an action) to use this userID to find the user data in my database. The reducer will then log that user in as if they hadn't cruelly refreshed the website.
Was this a good idea: NO! but also Yes!
Is this a secure way to store user ID's and keep track of who's logged in. NO!
But it's simple and can definitely be used for less critical data. And in my case it's ke[t my program running until I can come back and add the more secure log in functionality. So it's still useful.
Top comments (9)
Nice, ive been assigned to learn local storage, your explanation is good but could you please share any demo regarding this would be helpful,
sure - here is the repo for where I use it:
github.com/kevhines/speed-reader
specifically look at the index.js and App.js files in speed-reader-frontend/src/
I made a react hook for localstorage if that's of any interest 🙂
React: Custom hook for accessing storage
Andrew Bone ・ Apr 21 ・ 8 min read
thanks for sharing! That's great stuff!
I think you need to use sessionstorage as compared to localstorage because sessionstorage terminate session after browser close but localstorage don't do it.
Yeah, I didn't know the difference between those when I started.
I've since read this:
robinwieruch.de/local-storage-react
In either case I don't love them as long term solutions so I'll probably stick with localstorage for now.
That would depend on the use case.
Nice article. Btw. you're still using class components?
yeah, this program was part of a class project I did at the Flatiron School - they taught React with Class components so that was required in the final project.
We also learned a little bit about hooks and I plan to explore those more in my next project.