skip to Main Content

I’m creating a client-side only mockup of a gym-class management system. I have a models folder with javascript dummy user objects that will provide default user credentials and info. However, I want users to log in (using dummy credentials) and then be able to play around with the functionality by editing personal info, scheduling classes, etc. I do want persistent data across different sessions so I’m using localStorage as the "database". The project is very small so I wasn’t concerned about the storage size limits. Right now, I have programmed it so that logging in sets both the global authorized user state and sets the localStorage with the user object and all of its properties.

When it comes to the actual functionality (such as editing profiles or something), I’m lost on whether I should:

  • alter localStorage => then have a useEffect that syncs state with storage changes
  • alter state => then have a useEffect that syncs storage with state changes
  • just update both

For example, I have a widget component that would track to-dos for admin users. In the user object, I have a nested todos array. So far I’ve programmed it so that when the admin CRUD operates on the todo widget, it updates the user.todos property in both authState and localStorage user object. I’m currently just wondering whether there is a "best practice" for these kind of client-side-only mockups.

2

Answers


  1. I would avoid using useEffect unless necessary. It would probably make the most sense to update state immediately for the best user experience, and then in the same event handler, update local storage. I would only pull from local storage on load.

    Login or Signup to reply.
  2. You should apply the second option: "alter state => then have a useEffect that syncs storage with state changes".

    • The first option "alter localStorage => then have a useEffect that syncs state with storage changes" won’t work because localStorage is non-reactive, meaning that updates to localStorage won’t trigger a React component re-render for the useEffect hook to run again and pick up any changes.

    • The third option "just update both" is also ok, but may result in code that is less DRY because you end up duplicating the code/logic that persists changes out to localStorage in each handler that is enqueueing state updates. The useEffect hook is a single unit that handles reacting to the state updates enqueued from anywhere.

    You will use all three:

    • useState hook to represent the "source of truth" that users will edit/update. The state will be lazily initialized from localStorage.
    • useEffect hook to persist React state updates to localStorage.
    • localStorage to be the longterm storage, e.g. the "DB".

    The basic setup/usage will look similar to the following:

    const initialState = {
      ...
    };
    
    const MyComponent = () => {
      const [myState, setMyState] = React.useState(() => {
        // Return any persisted state, otherwise return base initial state
        return JSON.parse(localStorage.getItem("myState")) || initialState;
      });
    
      React.useEffect(() => {
        // Persist all state updates out to localStorage
        localStorage.setItem("myState", JSON.stringify(myState));
      }, [myState]);
    
      ...
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search