Useful boilerplate snippets which help me.
Table of contents
Open Table of contents
React-Query
Popular server-side caching library for React that provides useful hooks to manage data fetching, caching, synchronization, and state management.
Setting up
npm install @tanstack/react-query
// queryClient.ts
import { QueryClient } from '@tanstack/react-query';
const queryClient = new QueryClient();
export default queryClient;
Wrap your App.ts / Main.ts with the QueryClientProvider
// App.ts
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { QueryClientProvider } from '@tanstack/react-query';
import queryClient from './queryClient';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
Fetching data
I create my fetch requests in seperate files depending on the data such as fetchProducts.ts
which contains all the fetch requests related to products
, I then import them into the useQuery
hook. For this example I will use the FakeStoreAPI
and use products
and id
as the keys.
// fetchProducts.ts
export const getProducts = async () => {
const res = await fetch(`https://fakestoreapi.com/products`);
return res.json();
};
Then I create my useQuery hooks in a seperate file such as customHooks.ts
.
// customHooks.ts
import { getProduct } from "./imports";
export const useGetProduct = (id: number) => {
const { data: product, isLoading } = useQuery({
queryKey: ["product", id],
queryFn: () => getProduct(id),
});
return { product, isLoading };
};
Now I can then import the query into any of my components. In this instance I am using the FakeStoreAPI
and getting the first product using the initial ID value as 1
, everytime I click the button it will increase the ID by 1 until it gets to 20 which then resets to 1.
// Product.ts
import { useState } from "react";
import { useGetProduct } from "./customHooks";
const Product = () => {
const [id, setId] = useState<number>(1);
const { product, isLoading } = useGetProduct(id);
const { title } = product ?? {};
const changeId = () => {
if (id === 20) {
setId(1);
} else {
setId((prev) => prev + 1);
}
};
return (
<main>
<h3>Products</h3>
{isLoading ? (
<p>LOADING...</p>
) : (
<div>
<h4>{title}</h4>
</div>
)}
<button onClick={changeId}>Change ID</button>
<p>Current ID: {id}</p>
</main>
);
};
export default Product;
This video is a good way to visual one of the main benefits of React-Query
. As each time the button is pressed it will cache the data using the product
and id
key, if we encounter a new product you can see a flicker of a loading state. But once we have seen every product we can see from the second loop that each product is cached as no loading states appear.
Zustand
My preferred state management which I use in medium - large projects.
Setting up
npm install zustand
// useStorePrice
import { create } from "zustand";
interface StringStore {
price: number;
setPrice: (prc: number) => void;
}
const usePriceStore = create<StringStore>((set) => ({
price: 0
setPrice: (prc) => set({ price: prc }),
}));
export default useStringStore;
Then we can import it into any component.
// Price.tsx
import React from 'react'
import usePriceStore from './usePriceStore.ts'
export default function Price() {
const { price, setPrice} = usePriceStore()
return (
<div>{price}</div>
)
}