DEV Community

loading...

Using LocalStorage with React

kevhines
A programmer first, then ran a comedy school for the UCB theater, now a programmer again.
・4 min read

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
       }
Enter fullscreen mode Exit fullscreen mode

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}}
}
Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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)
    }
}
Enter fullscreen mode Exit fullscreen mode

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.

Discussion (9)

Collapse
cmuralisree profile image
Chittoji Murali Sree Krishna

Nice, ive been assigned to learn local storage, your explanation is good but could you please share any demo regarding this would be helpful,

Collapse
kevhines profile image
kevhines Author • Edited

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/

Collapse
link2twenty profile image
Andrew Bone
Collapse
kevhines profile image
kevhines Author

thanks for sharing! That's great stuff!

Collapse
daniel4lm profile image
Daniel Molnar

Nice article. Btw. you're still using class components?

Collapse
kevhines profile image
kevhines Author

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.

Collapse
faiqfarzan profile image
Muhammad Farzan Faiq

I think you need to use sessionstorage as compared to localstorage because sessionstorage terminate session after browser close but localstorage don't do it.

Collapse
kevhines profile image
kevhines Author

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.

Collapse
tbm206 profile image
Taha Ben Masaud

That would depend on the use case.