dai-shi / react-hooks-global-state

[NOT MAINTAINED] Simple global state for React with Hooks API without Context API
https://www.npmjs.com/package/react-hooks-global-state
MIT License
1.1k stars 62 forks source link

getState for non-redux version #15

Closed vans163 closed 5 years ago

vans163 commented 5 years ago

There is no getState for createGlobalState (the one you use without redux).

So its not possible to get the state inside a non-react functional component without write this hack.

    var state;
    setGlobalState('login', v => {
      state = v;
      return v;
    });
dai-shi commented 5 years ago

Hm, but why do you want a copy of global state?

This library by design doesn't expose entire global state. The apis are only allowed to access a part of global state by a property name. getState by createGlobalStore is just an exception to mimic Redux.

Oh, I may misunderstood. You want to read state outside react like getGlobalState('login'). It sounds like you want something like Redux middleware, which is not currently possible with createGlobalState. Hmmm.

vans163 commented 5 years ago

How would you handle a function like:

function apiCall() {
    var i_want_state;
    var do_stuff_with_state = i_want_state.key;
}

useGlobalState does not work here, as this is not a react component. I simply exported getState + write a getState/1, and it works great for me. So I can do now..

var full_state = getState();
var keyed_state = getState("navbar");

Maybe this should be added?

dai-shi commented 5 years ago

function apiCall() {

How would you call this? If this were called from useEffect, you could pass a state as a argument.

I really hesitate exporting getState which is likely to be misused, but at the same time I do understand without it, we are not providing the same-level api as createStore can do with middleware.

I would like to understand your use case: apiCall not triggered by useEffect but needs to read state?

dai-shi commented 5 years ago

Hm, interesting:

https://twitter.com/dai_shi/status/1132427865654349825

This library keeps global state outside of React. (which BTW is not a good design, hm I might be able to fix it.)

The moment after I start thinking about the design again, it seems to me that one of the values of this library is actually "keeping a copy of global state" outside of React. That would only allow us to use Redux-like middleware. And it would rather make sense to provide the same API for createGlobalState.

which is likely to be misused

Let me try limiting getState can only be called outside of React.

vans163 commented 5 years ago

"How would you call this? If this were called from useEffect, you could pass a state as a argument."

Calling it from ANYWHERE is broken (even inside a component). It does not work. Here is another example:

function apiQueryDatabase() {
    if (now() - CANT_GET_STATE.last_query >= 5000) {
        updateGlobalState(.., loading: true)
        await query();
        updateGlobalState(.., loading: false, last_query: now())
    }
}

Notice CANT_GET_STATE, basically we have no way to reference the state here, and MUST use redux. Why cannot do this without redux?

dai-shi commented 5 years ago

I was thinking about re-designing to be more hook-friendly, but gave up for now.

For now, the best is to add getGlobalState. Two things to note.

Please try #18 and let me know how it works or not.

dai-shi commented 5 years ago

Why cannot do this without redux?

To be clear, my recommendation of this library is createGlobalState, and createStore is only an option for people who would really want it. So, your feedback is valuable for me.

CANT_GET_STATE.last_query

I'm curious, in this example, do you have a component render with last_query? Otherwise, I wouldn't put in the globalState, but just keep in a variable.

vans163 commented 5 years ago

I'm curious, in this example, do you have a component render with last_query? Otherwise, I wouldn't put in the globalState, but just keep in a variable.

I use a differential state system. The backend always sends the frontend the updated state via WebSockets. So state does not soley start/end at the frontend for me, I have responsive realtime state between multiple sessions (if same user) across different computers, as soon as 1 user updates something, all users must get the update immediately.

The simplest way to achieve this for me and to prevent tons of extra network traffic, was to use evented streaming state differentials.

Hence why I often need to getState, simply to check what the state differential spit out. Using local state could work, but often I found that it was always missing something, like I would need to xref something in globalState regardless, then I would have to start caching a bunch of stuff locally and passing a buncha args, very quickly the code becomes a mess and we regress to react+classes.

dai-shi commented 5 years ago

@vans163 Haven't had a chance to try #18? Just pinging you to see if you are still interested in it. No rushing.

vans163 commented 5 years ago

Ah let me try it. So getWholeGlobalState() to get all state, and getState(key) for keyed?

dai-shi commented 5 years ago

Actually not. Only exported for createGlobalState is getGlobalState(key).

vans163 commented 5 years ago

Is it possible to export both? Just for utility? Give a person a swiss army knife, not a fork, a knife, and scissors as 3 separate objects.

Is it possible to merge this into master?

dai-shi commented 5 years ago

In short, I would only export keyed API. If someone really need a whole object, one can do the following:

const getWholeGlobalState = () => {
  const obj = {};
  Object.keys(initialState).forEach((key) => {
    obj[key] = getGlobalState(key);
  });
  return obj;
};

This is a bit of extra work, and one should use getGlobalState(key) whenever possible.


What's important here is that the fact that this library uses observedBits is an implementation detail, and React may drop this API at any time. If it's simply dropped, I would change the implementation to use multiple contexts and the getWholeGlobalState might be implemented just like the above. I believe that exporting getWholeGlobalState encourages the misuse of it.

vans163 commented 5 years ago

The problem with useGlobalState again is, it only works inside react components. Maybe I am missing the correct way to create a root level store like redux does, due to my lack of react skills.

dai-shi commented 5 years ago

@vans163 Oops, sorry. I meant getGlobalState(key).

dai-shi commented 5 years ago

Anyway, let's merge #18.

dai-shi commented 5 years ago

https://www.npmjs.com/package/react-hooks-global-state/v/0.12.0