dai-shi / react-hooks-global-state

[NOT MAINTAINED] Simple global state for React with Hooks API without Context API

Home Page:https://www.npmjs.com/package/react-hooks-global-state

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

comparison to react-tracked and initial values for a state

dohomi opened this issue · comments

Hello,

I'd like to know about the difference between react-tracked and react-hooks-global-state. I am using your package and just thought I'd like to know the differences.

One thing I have in mind: I am using your package to set a global settings object coming from a headless CMS. I use NextJS and the settings being received from the server through getInitialPageProps. Now I'd like to make them globally available because many components are in need to get these values.

const [appSettings, setAppSettings] = useGlobalState('settings') // => how can I set these object on the first render? 

It would be great if useGlobalState would offer the default/initial values that I don't need a useEffect to set my app settings.

Hey, thanks for asking. Actually, it's a very good question. There are two aspects.

API

react-hooks-global-state offers the property-based accessor useGlobalState(name) where name has to be a property (string).

react-tracked provides useTrackedState which is a unique API with "state usage tracking". It will track the state object usage in deep (even nested objects are tracked) and only trigger re-renders if the used part of the state is changed. It also provides useSelector which is similar to the one in React Redux.

Store

react-hooks-global-state has an external store just like Redux. Although it's tied to React unlike Redux, it's definitely defined outside React.

react-tracked has a state internally in the React component. You can only update through React just like normal React state + context.


Now I'd like to make them globally available because many components are in need to get these values.

In your use case, you'd need to use useEffect for updating state inside React. This is always true in react-tracked. In react-hooks-global-state, as the store is external, you can update the state without useEffect. There's setGlobalState for that purpose. Check out examples/04_fetch, examples/05_onmount and __tests__/03_startup_spec.tsx.


A general note about external stores: With upcoming Concurrent Mode, there's useTransition hook which allows "branching state". This is only possible with state inside React. So, react-hooks-global-state won't get benefits from that feature. react-hooks-global-state should still be CM-safe though.

@dai-shi thanks for your detailed answer. I just started using setGlobalState and getGlobalState on my index.tsx file to fill my global state settings with its values. As the settings will never change once being set i just simply proof if the state changed through getGlobalState

const setSettings = (settings: GlobalStoryblok) => {
  const currentSettings = getGlobalState('settings')
  if (!currentSettings._uid) {
    setGlobalState('settings', settings)
  }
}

Is it safe if the settings is being a very huge JSON object? I just want to avoid to pass settings as props because its been needed in so many files within my app.
So in my child nodes I use useGlobalState('settings') as a read-only variant to get access to my settings props. Would you think this is legitimate way of doing it?

Is it safe if the settings is being a very huge JSON object?

Yes, it is safe. It's just like a JS global variable.

Would you think this is legitimate way of doing it?

Yeah. The only concern is what you give for the initial settings value and how a component renders with it before it gets the final settings value.


const setSettings = (settings: GlobalStoryblok) => {
  const currentSettings = getGlobalState('settings')
  if (!currentSettings._uid) {
    setGlobalState('settings', settings)
  }
}

Although this works, I wonder if there's a better way. What would you provide initial date to createGlobalState? Isn't it straightforward to check the existence outside of this function? Maybe, maybe not.

@dai-shi this is my component structure:

getInitialProps => fetches settings from my CMS with API call
index.tsx => calls `setSettings(settings)` from props of the getInitialProps 
layout.tsx => child of index useGlobalState('settings') has the correct value initially

I guess the order and component structure matters. But as my initial index.tsx receives the settings as props and sets immediately the global state the child component has already the correct value on initial first render as far I could see.
The best would be if createGlobalState might be called on the initial first render inside index.tsx but not sure if thats possbile nor a good way or rather a hack

createGlobalState must be called outside render.

Neigher update nor setGlobalState can't be called in render. (React 16.13 will warn it.)

I'm not very familiar with Next, but what's the normal/recommended usage in your use case in Next? Using useEffect? What you could do is calling setGlobalState inside getInitialProps, but that may look weird.

In your use case, is it correct that you get settings from one of the pages, and you want to use the settings in other pages?

@dai-shi as the index.tsx is the parent component of all files it seems to work fine as long I don't make use of the GlobalState variable in the index.tsx file. I make use of the settings prop in 42 files so I thought it might be smart to keep it as a local variable rather passing it on inside of props all the time. Not sure if I am breaking out of React with this approach though..

Hm, if index.tsx is the root component and you get settings as a prop, it might fit well to use the native React context. Have you considered that?

@dai-shi fair point, I am doing that for some other vars. I think for now I stick to the use of the settings as props as I did it already that way and will continue using GlobalState for things like left/right navigation drawer opening state and so on. It was a good learning process though, the get/set outside of react is definitely a nice way for me setting global vars and re-use their value in React context and outside of that context. Thanks a bunch for your input though!

You are welcome!