Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I've used React Query and Zustand extensively in my projects, and unfortunately Zustand suffers from the same issue in cases where you aren't dealing with async data. I'm talking about React state + data that's already available, but can't be used to initialize your store before the first render cycle.

Here's how Zustand gets around this, and lo-and-behold: it requires React Context :( [1] (Look at how much boilerplate is required!)

React Query at least gives you an `initialData` option [2] to populate the cache before anything is done, and it works similarly to `useState`'s initializer. The key nuance with `const [state, setState] = useState(myInitialValue)` is the initial value is set on `state` before anything renders, so you don't need to wait while the component flashes `null` or a loading state. Whatever you need it to be is there immediately, helping UIs feel faster. It's a minor detail, but it makes a big difference when you're working with more complex dependencies.

1. https://zustand.docs.pmnd.rs/guides/initialize-state-with-pr...

2. https://tanstack.com/query/v5/docs/framework/react/guides/in...

---

I guess I could abuse React Query like this...

  function useGlobalStore() {
    const myHookState = useMyHook(); // not async

    return useQuery({
      initialData: {
        optionA: true,
        optionB: myHookState,
      }
    });
  }
And you'd have to use `queryClient` to mutate the state locally since we aren't dealing with server data here.

But here's what I really want from the React team...

  // Hook uses global instance instead of creating a new one each time it's used. No React Context boilerplate or ceremony. No wrapping components with more messy JSX. I can set state using React's primitives instead of messing with a 3rd party store:

  const useGlobalStore = createGlobalStore(() => {
    const dataFromAnotherHook = useAnotherHook();

    const [settings, setSettings] = useState({
      optionA: true,
      optionB: dataFromAnotherHook,
    });

    return {
      settings,
      setSettings,
    }
  });


I think it might already be working like that? React now has concurrent rendering, so it will try to optimistically render the DOM on the first pass. This applies even if you have hooks.

There is no real difference now between doing:

  const [state, setState] = useState(42);
and:

  const [state, setState] = useState(undefined);
  useEffect(() => setState(42));
They both will result in essentially the same amount of work. Same for calculations with useMemo(). It was a different situation before React 18, because rendering passes were essentially atomic.


Ah great point, I need to give this another shot and confirm. I only switched from 17 to 19 in the last few months here.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: