← Back to all blogs

Next-Gen Redux Toolkit- Best Practices with Jotai and TanStack Query

| November 10, 2024

Table of Contents

Introduction

TL;DR For optimal stability in your React applications, leverage Jotai or Zustand for client-side state management and TanStack Query for server-side state management. This combination not only enhances stability but also simplifies your state management strategy.

As of writing this article on November 11, 2024, I’m using the latest versions of the following packages:

{
"jotai": "^2.10.1",
"@tanstack/react-query": "^5.59.16",
}

Before diving into the integration process, let’s briefly overview the tools we’ll be using:


Why not redux toolkit?

Jotai with TanStack Query serves as a robust and business-ready alternative to Redux Toolkit. It addresses the complexities and tediousness often associated with Redux, making it more beginner-friendly. While I’ve always appreciated Redux Toolkit for its seamless integration with TanStack Query—solving issues like managing multiple component states and handling dependent state updates with ease—it becomes cumbersome when dealing with hundreds of component states. Additionally, Redux’s thunk for async state management becomes redundant when using TanStack Query.


Should You Use Only TanStack Query?

If you’re highly proficient with TanStack Query, it can be a one-stop solution for both client-side and server-side state management. Its high configurability offers great flexibility, but it requires careful attention to parameter settings.

Pro Tip: By default, TanStack Query caches data for 5 minutes. To ensure data persists indefinitely, set cacheTime: Infinity.


Quick Comparasion Example

const outputDatetimeAtom = atom("");
const inputIncludesTimezoneAtrom = atom(false);
const [outputDatetime, setOutputDatetime] = useAtom(outputDatetimeAtom);
const [inputIncludesTimezone, setInputIncludesTimezone] = useAtom(
inputIncludesTimezoneAtrom
);
import { useUserState } from './state/user';
export default function App() {
const { setData: setOutputDatetimeData, resetData: resetOutputDatetimeData } = useOutputDatetimeState();
...
}
src/state/useOutputDatetimeState.tsx
import { createGlobalState } from './createGlobalState'; // Adjust the path as necessary
type OutputDatetimeState = {
convertedDatetime: string;
};
export const useOutputDatetimeState = createGlobalState<OutputDatetimeState>(
'outputDatetimeState',
{
convertedDatetime: '',
}
);
src/state/createGlobalState.tsx
import { useQuery, useQueryClient } from '@tanstack/react-query';
export function createGlobalState<T>(
queryKey: unknown,
initialData: T | null = null,
) {
return function () {
const queryClient = useQueryClient();
const { data } = useQuery({
queryKey: [queryKey],
queryFn: () => Promise.resolve(initialData),
cacheTime: Infinity,
refetchInterval: false,
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
refetchIntervalInBackground: false,
});
function setData(newData: Partial<T>) {
queryClient.setQueryData<T | undefined>([queryKey], (oldData) => ({
...(oldData || {}),
...newData,
}));
}
function resetData() {
queryClient.invalidateQueries({
queryKey: [queryKey],
});
queryClient.refetchQueries({
queryKey: [queryKey],
});
}
return { data, setData, resetData };
};
}

Conclusion

Transitioning to Jotai combined with TanStack Query offers a streamlined and efficient approach to state management in modern React applications. This setup not only reduces boilerplate but also enhances scalability and maintainability.

Happy Coding!