donavon/use-persisted-state

Add reducer equivalent of the API

AndrewIngram opened this issue · 3 comments

This looks great, at first glance the main thing lacking is an equivalent of useReducer for more complex state management. Any interest in extending it a bit?

Hmm... Interesting. Have any ideas? Seems like a different package, but would share many of the same functionality.

useState is actually implemented in react using useReducer. The default reducer in this case is just (state, action) => typeof action === 'function' ? action(state) : action;

So it seems like it should be quite sufficient to add a parameter to usePersistedState and implement a createPersistedReducer (to keep a simple API and account for the fact that you fallback to the default state hooks).

It gets tricky, though, because usePersistedState sets the state on storage change events and when another instance emits a setState event. In contrast, when using useReducer, dispatch never explicitly gets the state, so we can't really use useReducer.

That being said, there's a neat package react-enhanced-reducer-hook that augments useReducer in a clever way--by using setState and implementing dispatch itself. Looks like this library could use a similar strategy to implement a useReducer variant.

A small preliminary sketch:

const createPersistedReducer = (
  key,
  provider = global.localStorage,
  reducer = (state, action) => typeof action === 'function' ? action(state) : action,
) => {
  if (provider) {
    const storage = createStorage(provider);
    return initialState => usePersistedReducer(reducer, initialState, key, storage);
  }
  return useReducer;
};

with usePersistedReducer being:

// Omitting code that stays the same
const usePersistedReducer = (reducer, initialState, key, { get, set }) => {
  // ...same ...
  const dispatch = action => {
    const next = reducer(state, action);
    setState(next);
    return action;
  };

  // ... same ...

  return [state, dispatch];
};

Alternatively, depending on how much you want to condense down the code changes, I can see all of this extra functionality being added in with ~5 lines of changed code by adding a conditional or two to the existing functions.

@jared-w

Sorry it's taken been so long to respond. I've got a lot of pokers in the fire at once.

This is a great plan. I'll try to get this implemented as soon as I can. I'm going something similar in a different project.