description | keywords | date | author | |||||
---|---|---|---|---|---|---|---|---|
Introducing Floppy Disk, the Zustand-ReactQuery alternative for local, global, sync, or async state management. |
Floppy Disk, React, State Management, JS, JavaScript, NPM, Store, TanStack-Query, Zustand, Alternative |
2023-10-01 07:13:23 UTC |
|
import Meta from './_components/Meta';
The Zustand-ReactQuery alternative for local, global, sync, or async state management.
In the beginning, I made this library just as part of my learning journey. Not trying to re-invent the wheel, but I just want to challange myself whether I can build something like that.
I always thought Zustand & TanStack-Query (a.k.a React-Query) were really cool. I love the simplicity of Zustand. I am truly impressed with the completeness of the features offered by React-Query. So, it will be a really huge challange to replicate both functionalities.
In the end, I managed to replicate more than 90% of their functionalities (see comparison), with the developer experience I desired, and some additional advantages.
- Zustand-Query
In the initial phase, I try to re-create something like React-Query using Zustand. A "Zutand-Query" 😆. But then I encountered difficulties because in Zustand, there is no store "key" that can be used as a query key. I feel like there is no way out unless I create something like Zustand, but with more power.
- Zustand++
As I mentioned previously, finally I create a Zustand-like state manager, but with more features:
- Go Deeper Into React-Query and SWR
In this phase, I learned about: how to serialize a query key into a string, the different options naming between React-Query & SWR, the behavior of bi-directional query, race-condition prevention, React suspense, and many more.
- The Born of Floppy Disk
Finally I managed to create:
- A global state manager just like Zustand.
- A data fetching state manager just like TanStack Query & SWR, but it tastes like Zustand.
- A smaller bundle size package.
import { create } from 'zustand'; // 3.3 kB (gzipped: 1.5 kB)
import { createStore } from 'floppy-disk'; // 1.4 kB (gzipped: 725 B) 🎉
import { QueryClient, QueryClientProvider, useQuery, useInfiniteQuery, useMutation } from '@tanstack/react-query'; // 41 kB (gzipped: 11 kB)
import { createQuery, createMutation } from 'floppy-disk'; // 9.6 kB (gzipped: 3.2 kB) 🎉
In the end, I managed to replicate more than 90% of their functionalities (see comparison), with the developer experience I desired, and some additional advantages.
I want to explain the developer experience part and the additional advantages part.
I'm not a fan of the experience in React-Query regarding the use of a query key to refer a query. It's a bit difficult to ensure its uniqueness. In React-Query, we can't be 100% sure if there is no duplicate query key, even if we already use Query Key factories.
const MY_QUERY = 'my-query';
const MY_OTHER_QUERY = 'my-query'; // 🔴
const myQuery = useQuery([MY_QUERY], myQueryFn);
const myOtherQuery = useQuery([MY_OTHER_QUERY], otherFunction); // 🔴
const state = queryClient.getQueryState({ queryKey: MY_QUERY });
// ^ Is this state comes from myQueryFn or otherFunction?
In Floppy Disk, we refer a query with the query object itself, no ambiguity:
const useQuery = createQuery(myQueryFn);
const myOtherQuery = createQuery(otherFunction);
useQuery.get();
myOtherQuery.get();
useQuery.invalidate();
myOtherQuery.invalidate();
Floppy Disk gives a simpler code for optimistic update, which automatically cancel the pending query to prevent race condition, and return a revert & invalidate function.
const { revert, invalidate } = useProfileQuery.optimisticUpdate({
response: payload,
});
// Specific id:
const { revert, invalidate } = useProductDetailQuery.optimisticUpdate({
key: { id: payload.id },
response: payload,
});
In Floppy Disk, bi-directional query is treated like 2 independent infinite query. So, we can start refetch from the initial page and have a parallel refeching for next & previous pages. Therefore, we can obtain the information in which direction we are fetching/refetching.
React-Query:
Initial:
- Initial fetch (page 5)
- Fetch next (page 6)
- Fetch previous (page 4)
Pages: [4, 5, 6]
Refetch:
- Refetch (page 4)
- Fetch next (page 5)
- Fetch next (page 6)
Floppy Disk:
Initial:
- Initial fetch (page 5)
- Fetch next (page 6)
- Fetch previous (page 4)
Pages: { next: [5, 6], prev: [4] }
Refetch:
- Refetch initial page (page 5)
- Fetch next pages (page 6) and previous pages (page 4) parallelly sequentially
It was inspired from this issue: TanStack/query#1401.
There are some other improvement:
Zustand & React-Query are awesome production-ready library. If you love both libraries, then I think you should try Floppy Disk, but might not need to switch to it, unless it really solved the problem you encounted when using Zustand/React-Query.
I put a data in it, and it was a tiny store, then "Floppy Disk" comes to my mind.