pmndrs / zustand

🐻 Bear necessities for state management in React
https://zustand-demo.pmnd.rs/
MIT License
47.38k stars 1.46k forks source link

Extract the logic that makes hook shareable without Provider/Context #9

Closed timkindberg closed 5 years ago

timkindberg commented 5 years ago

I'm loving the look of this lib! I'm currently rewriting some of my state management as a POC using it.

I was curious, would you be able to extract the logic that makes this hook "shareable" in any component without needing a Provider? If so that extracted utility would be highly valuable to the hook community. Any hook could use this utility to convert the regular hook to a "works anywhere as a singleton" hook.

Or is the "sharing" capability too coupled with the rest of the library?

Thinking something like this:

// This hook could now be used in many places with the same reference state.
const useSharedState = share(() => {
  const [state, setState] = useState(initialState)

  return [state, setState]
})

Some prior art are:

drcmda commented 5 years ago

well it doesn't need a provider because it's not context based. these hooks work everywhere, even outside of react bounds, like reconcilers. the hook you create already is a shared connector, that can be used anywhere in your app.

or maybe i don't understand it yet, could you go into shared state a little more deeper?

timkindberg commented 5 years ago

Sorry, let me try to explain again.

Your library is two things to me:

  1. A way to share state with many components without using Provider
  2. An elegant state API

1 is a worthwhile discovery on its own. 2 is also good because you value simple APIs. Each could have been built independently, with 2 being built using 1.

But what if someone loves reducers or something else? I know you allow middleware for API customization, but your lib still has opinions. It would be cool if there was a lower-level share higher-order hook that converted any state-based hook to a "shared" state-based hook, without the need to use a Provider. Then your opinionated API would be built on top of this share hook, as a higher-level API.

drcmda commented 5 years ago

reducers are no problem though

const types {
  increase: "INCREASE",
  decrease: "DECREASE"
}

const reducer = (state, { type, ...payload }) => {
  switch (type) {
    case types.increase: return { ...state, count: state.count + 1 }
    case types.decrease: return { ...state, count: state.count - 1 } 
  }
  return state
}

const [useStore] = create((set, get) => ({
  count: 0,
  dispatch: args => set(state => reducer(state, args)),
})

Maybe give me some code examples, need to see it to imagine how it works.

timkindberg commented 5 years ago

I'm thinking more if someone already had a hook written.

function useMyState() {
  const [state, dispatch] = userReducer(...)
  const actions = {...}
  // maybe some more logic
  return someApi
}

Then they could just make it "shared" state, meaning it could be used in multiple components. Like a higher-order hook.

export useMySharedState = share(useMyState)

Anyway, sorry to beat a dead horse :) THANK YOU for this library, we've started using it in our startup's site. It's going well so far!

JeremyRH commented 5 years ago

This would be nice but I don't know if your example is possible. State is shared without using a provider by collecting the setState and dispatch functions in a list and calling them when needed. It is possible for someone to create a package that does this though:

import { useReducer, useState } from 'react';
import share from 'react-share-state';
export const useSharedReducer = share(useReducer);
export const useSharedState = share(useState);
JeremyRH commented 5 years ago

I'm going to close this for now as it seems like this is something another library could solve.