简体   繁体   中英

What pattern does the library react query uses (hooks with OOP)?

I have seen a pattern from the react-query library which does the following:

(OOP)

// it instantiates an object from a class
const queryClient = new QueryClient()

(Hooks)

// Then it passes this object as a prop to the provider

<QueryClientProvider client={queryClient}>
  <Todos />
</QueryClientProvider>

and in the <Todos /> component, this library gives you the option to both use the client or use a hook.

// Todos

const client = useQueryClient(); // (Hook)

const query = useQuery( key, fn, option ); // (Hook) 

What I cannot understand is how this library is able to keep its state in sync between a normal javascript class object namely the client and the usage of other hooks. What I mean by that is for example, you are able to use the hook useQuery with a key as the first argument and what this hook does is that executes the fn function and stores the result in a data property inside the query .

The funny part is that you can then use this data by calling the following method from the client .

const { data } = client.getState(key);

So what it actually does behind the scenes in order to keep in sync both a classic javascript object and hooks?

const client = useQueryClient(); // (Hook)

const query = useQuery( key, fn, option ); // (Hook) 

// ----> in sync : query.data === client.getState(key).data

Its because the source of truth is that query-client object. It contains the caches (also classes) and a bunch of methods to access them and so on.

I suppose you could instantiate it in some module, and then import it and access it if all you wanted to do was to hold mutable state in some object somewhere. But part of the charm is to marry the calling of cached functions and access of that state to react: Have the queries be called when a component mounts, and have other components that are interested in the same result all wait for the same result. Have newly mounted components investigate if the data is stale. Refetch data on a timer, but only one for all components, and so on and so on.

The integration into the react lifecycle functions via hooks (all modern react libraries with self respect gotta have some hooks,): because they can slip into your components lifecycle in a simple and declarative way. "use" some resource.

These hooks then employ reacts lifecycle hooks, and the cache and methods in the QueryClient. Because the QueryClientProvider provides the queryClient through a react context, you don't have to export/import your instantiated QueryClient throughout your modules, they find it themselves.

There's a lil trick in the module top-level defining the react context here

I made a little codesandbox you can check out here

If you want to brush up on the observer pattern you can do so here

And compare with this walkthrough on app state without context.

Also, don't forget how using object references as function parameters can have side effect .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM