Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add reducer equivalent of the API #3

Open
AndrewIngram opened this issue Feb 11, 2019 · 3 comments
Open

Add reducer equivalent of the API #3

AndrewIngram opened this issue Feb 11, 2019 · 3 comments
Labels
enhancement New feature or request

Comments

@AndrewIngram
Copy link

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?

@donavon
Copy link
Owner

donavon commented Feb 12, 2019

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

@donavon donavon added the enhancement New feature or request label Feb 16, 2019
@hazelweakly
Copy link

hazelweakly commented Mar 8, 2019

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.

@donavon
Copy link
Owner

donavon commented Mar 18, 2019

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants