Skip to content

Introducing TanStack Query v5: A Leap Forward in Simplicity and Functionality

Introducing TanStack Query v5: A Leap Forward in Simplicity and Functionality

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

TanStack Query v5: A Leap Forward in Simplicity and Functionality

Introduction:

Here at ThisDot we totally love TanStack Query, so we are really excited to share the news about the release of TanStack Query v5, the latest version of the powerful data-fetching library. The TanStack Query team has been hard at work, making significant improvements to enhance the library's usability and functionality. This blog post will explore the exciting new features and changes introduced in v5.

Breaking Changes:

One of the most notable changes in TanStack Query v5 is the removal of most overloads from the codebase. Previously, different overloads were used when calling useQuery and other hooks, resulting in inconsistent usage patterns and subpar TypeScript error messages. With the introduction of TypeScript 4.7, the team was able to unify the usage of these hooks, resulting in a more consistent and streamlined API. Now, developers only need to pass a single object, making the API more intuitive and developer-friendly. To assist with the transition, the team has updated the documentation, released an auto-fixable eslint rule, and provided a codemod tool.

New Features:

TanStack Query v5 introduces a range of exciting new features that enhance the data-fetching experience. Let's explore some of them:

  1. Simplified Optimistic Updates: Performing optimistic updates is now easier than ever with the useMutation hook. Developers can leverage the returned variables without manually updating the cache. This streamlined approach simplifies the process and improves efficiency.

  2. Sharable Mutation State: A highly requested feature, the useMutationState hook allows developers to access the state of all mutations across components. This shared state simplifies coordination and management of mutation-related data.

import { useMutation, useMutationState } from 'tanstack-query';

const mutationKey = ['example']

const mutation = useMutation({
	mutationKey,
	mutationFn: (...) => {
		...
	},
})

// In another component
const data = useMutatationState({
// this mutation key needs to match the one of the given mutation ('example' in our case)
	filters: { mutationKey },
	select: (mutation) => mutation.state.data, 
})

  1. 1st Class Suspense Support: TanStack Query v5 fully supports suspense for data fetching. Hooks like useSuspenseQuery, useSuspenseInfiniteQuery, and useSuspenseQueries enable seamless integration of suspense in applications, providing a more efficient and intuitive way to handle data fetching.

  2. Streaming with React Server Components: The new version introduces an experimental integration for suspense on the server in Next.js. By leveraging the react-query-next-experimental adapter, developers can initiate data fetching during server-side rendering (SSR) and stream the result to the client, combining interactivity and data synchronization.

  3. Improved Infinite Queries: Infinite Queries now supports prefetching multiple pages simultaneously, allowing developers to optimize performance. Additionally, the maximum number of pages stored in the cache can be specified, providing more control over memory usage.

// infinite query can be prefetched as a normal query
const prefetchExample = async () => 
	await queryClient.prefetchInfiniteQuery({
		queryKey: ['...key name...'],
		queryFn: fetchFn,
		initialPageParam: 0,
		getNextPageParam: (lastPage, pages) => lastPage.nextCursor, // this is needed when you want to prefetch more than one page
		pages: 5 // prefetch the first 5 pages
	})
  1. New Devtools: The Query devtools have been completely rewritten in a framework-agnostic manner, making them accessible to all adapters. With a revamped UI and new features like cache inline editing and light mode, developers can benefit from enhanced debugging capabilities.

  2. Fine-Grained Persistence: Addressing a long-standing discussion, v5 introduces fine-grained persistence with the experimental_createPersister plugin. This plugin enables developers to persist queries individually, offering just-in-time restore capabilities, particularly beneficial for mobile development.

  3. The queryOptions API: With the unified useQuery API, v5 introduces the queryOptions function, enabling type-safe sharing of query definitions between useQuery and imperative methods like queryClient.prefetchQuery. This enhancement improves code maintainability and type safety.

import { queryOptions } from 'tanstack-query'

function groupOptions(){
	return queryOptions({
		queryKey: ['...key name...'],
		queryFn: fetchFn,
		staleTime: ...
	}) 
}

useQuery(groupOptions())
queryClient.prefetchQuery(groupOptions())

Conclusion:

TanStack Query v5 marks a significant milestone in the evolution of the data-fetching library. The breaking changes and new features introduced in this version enhance the developer experience, simplify usage, and open up exciting possibilities for data management. We encourage fellow developers to explore the migration guide, check the docs and leverage the examples provided to make the most of TanStack Query v5. Upgrade today and experience the future of data fetching with TanStack Query!

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

Building interactive forms with TanStack Form cover image

Building interactive forms with TanStack Form

TanStack Form is a new headless form library that makes building more complex and interactive forms easy. TanStack has understood the power of ‘headless’ UI libraries for quite some time with some really incredible tools like TanStack Table and TanStack Query. Given the high quality of all the other libraries in the TanStack suite, I was excited to give this new form library a try. If you’ve used react-hook-form before the two libraries have quite a bit in common. The transition should be mostly straightforward. Let's start by comparing the two libraries and bit and then dig into the TanStack Form API with some examples and code. Comparison to react-hook-form At a high level, the two libraries are pretty similar: - Headless, hook-based API - Performance (both libraries minimize amount of renders triggered by state changes) - Lightweight, zero-dependencies (TanStack 4.4kb, react-hook-form 9.7kb) - Comprehensive feature set - Type-safety / TypeScript support - Form / Input validation and schemas There are a few things that set TanStack Form apart: - UI Agnostic - TanStack Form offers support for other UI libraries and frameworks through a plugin-style system. Currently, React & Solid is supported out of the box. - Simpler API and documentation - The API surface area is a bit smaller, and the documentation makes it easy to find the details on all the APIs. - First-class TypeScript support - TanStack Form provides really impressive type inference. It stays out of your way and lets you focus on writing code instead of wrangling types. Building forms Since the API for TanStack Form is pretty small, we can walk through the important APIs pretty quickly to see how they work together to help us build interactive client-side forms. useForm(options) useForm accepts an options object that accepts defaultValues, defaultState, and event handler functions like onSubmit, onChange, etc. The types are clear, and the source code is easy to read so you can refer to FormApi.ts file for more specifics. Currently, the examples on the website don’t provide a type for the generic TData that useForm accepts. It will infer the form types based on the defaultValues that are provided, but in this example, I will provide the type explicitly. ` The API for your form is returned from the useForm hook. We will use this API to build the fields and their functionality in our component. useField(opts) If you want to abstract one of your form fields into its own component we can use the useField hook. The useField generic parameters take the type definition of your form and the field name. ` Validation is as simple as returning a string from your field onChange handler. For our password field we return an error message if the length isn’t at least 8 characters long. We bind our field states and event handlers to the form input by passing them in as props. Component API form includes a component API with a Context Provider, a component for rendering Field components, and a Subscribe component for subscribing to state changes. I’ve added the remaining fields to our form using the Field component and included our PasswordField from above. Using the Field component is similar to using the useField hook - the difference is our field instance gets passed in via a render prop. ` We wrapped our submit button with the Subscribe component which has a pretty interesting API. Subscribe allows you to subscribe to state changes granularly. Whatever state items you return from the selector gets passed into the render prop and re-render it on changes. This will be really useful in places where render performance is critical. Async event handlers We can use the built-in async handlers and debounce options to implement a search input. This feature makes a common pattern like this trivial. ` Async event handlers can be used for other things like async validation as well. We could update our email input from our create account form to check to see if the account already exists. ` Validation adapters Since this post was first written, TanStack Form has added adapters for popular schema validation libraries like Yup and Zod. The actual API for using the schemas is a little bit different then what you might be used to from react-hook-form. Instead of passing a schema definition for all of the fields to the root form API, you provide schemas for each field individually. We’ll look at the Zod example from the documentation. ` To use the schema validation you need to pass the schema validation adapter into the validatorAdapter option in the useForm declaration. Looking at the FieldInfo component from the example we can see that the internal state and API for form validation is the same. The adapter takes care of wiring up the schema validation library to handle the underlying field validation. ` So we can easily check the state of our field to see if there are any errors or if it’s processing some async validation logic. We mentioned that without the schema adapter we can just return an error message string from a validation function to indicate an error. With the schema adapter, we instead just return the schema itself. This works for async validations as well. ` Initially, I wasn’t sure that I would like defining a schema at the field level instead of providing a schema up front for the entire form. After sitting with it for a bit, I think it’s a better solution. The validations are decoupled from the value of the field and it allows a clean and simple API to decide when they run. In the example above validations against the schema will run on every change to the field value but we could easily change this to onBlur or any of the other available event handlers. Conclusion If you don’t mind taking a chance on a newer library from a well-established author in the ecosystem, Tanstack Form is a solid choice. - The APIs are easy to understand, and it has some nice async event handling features that are extremely useful. - It includes adapters for using schema validation libraries like Zod. - It is UI library/framework agnostic (currently has plugins to support React, React Native, and Solid) - Quality TypeScript support In my opinion, it’s the most intuitive and flexible form library out there. TanStack and all of its libraries are amazingly well designed. 10/10...

Awesome 3D experience with VueJS and TresJS: a beginner's guide cover image

Awesome 3D experience with VueJS and TresJS: a beginner's guide

Awesome 3D experience with VueJS and TresJS: a beginner's guide Vue.js developers are renowned for raving about the ease, flexibility, and speed of development their framework offers. Tres.js builds on this love for Vue by becoming the missing piece for seamless 3D integration. As a Vue layer for Three.js, Tres.js allows you to leverage the power of Three.js, a popular 3D library, within the familiar and beloved world of Vue components. This means you can create stunning 3D graphics and animations directly within your Vue applications, all while maintaining the clean and efficient workflow you've come to expect. TresJS is a library specifically designed to make incorporating WebGL (the web's 3D graphics API) into your Vue.js projects a breeze. It boasts several key features that make 3D development with Vue a joy: - Declarative Approach: Build your 3D scenes like you would any other Vue component, leveraging the power and familiarity of Vue's syntax. This makes it intuitive and easy to reason about your 3D elements. - Powered by Vite: Experience blazing-fast development cycles with Vite's Hot Module Replacement (HMR) that keeps your scenes updated in real-time, even as your code changes. - Up-to-date Features: Tres.js stays on top of the latest Three.js releases, ensuring you have immediate access to the newest features and functionality. - Thriving Ecosystem: The Tres.js ecosystem offers many resources to enhance your development experience. This includes: - Cientos: A collection of pre-built components and helpers that extend the capabilities of Tres.js, allowing you to focus on building your scene's functionality rather than reinventing the wheel (https://cientos.tresjs.org/). - TresLeches: A powerful state management solution specifically designed for 3D applications built with Tres.js (https://tresleches.tresjs.org/). You can try TresJS online using their official Playground or on their StackBlitz starter. But now, let's dive into a quick code example to showcase the simplicity of creating a 3D scene with TresJS. Setup First, install the package: npm install @tresjs/core three And then, if you are using Typescript, be sure to install the types: npm install @types/three -D If you are using Vite, now you need to modify your vite.config.ts file in this way to make the template compiler work with the custom renderer: ` Create our Scene Imagine a 3D scene as a virtual stage. To bring this stage to life, we need a few key players working together: 1. Scene: Think of this as the container that holds everything in your 3D world. It acts as the canvas where all the objects, lights, and the camera reside, defining the overall environment. 2. Renderer: This is the magician behind the curtain, responsible for taking all the elements in your scene and translating them into what you see on the screen. It performs the complex calculations needed to transform your 3D scene into 2D pixels displayed on your browser. 3. Camera: Like a real camera, this virtual camera defines the perspective from which you view your scene. You can position and adjust the camera to zoom in, zoom out, or explore different angles within your 3D world. - To make our camera dynamic and allow canvas exploration, we are going to leverage the client's OrbitControls component. Below are our examples. You will see that we just include the component in our canvas, and it just works. 4. Objects: These actors bring your scene to life. They can be anything from simple geometric shapes like spheres and cubes to complex models like characters or buildings. You create the visual elements that tell your story by manipulating and animating these objects. Starting from the beginning: to create our Scene with TresJS we just need to use our component TresCanvas in our Vue component's template: ` The TresCanvas component is going to do some setup work behind the scenes: - It creates a WebGLRenderer that automatically updates every frame. - It sets the render loop to be called on every frame based on the browser refresh rate. Using the window-size property, we force the canvas to take the width and height of our full window. So with TresCanvas component we have created our Renderer and our Scene. Let's move to the Camera: ` We just have to add the TresPerspectiveCamera component to our scene. NOTE: It's important that all scene-related components live between the TresCanvas component. Now, only the main actor is missing, let's add some styles and our object inside the scene. Our Vue component will now look like: ` And our scene will be: A Mesh is a basic scene object in three.js, and it's used to hold the geometry and the material needed to represent a shape in 3D space. As we can see, we can achieve the same with TresJS using the TresMesh component, and between the default slots, we are just passing our object (a Box in our example). One interesting thing to notice is that we don't need to import anything. That's because TresJS automatically generates a Vue Component based on the three objects you want to use in PascalCase with a Tres prefix. Now, if we want to add some color to our object the Three.js Material class comes to help us. We need to add: ` Conclusion Tres.js not only supercharges Vue.js applications with stunning 3D graphics, but it also integrates seamlessly with Nuxt.js, enabling you to harness the performance benefits of server-side rendering (SSR) for your 3D creations. This opens the door to building exceptional web experiences that are both interactive and performant. With Tres.js, Vue.js developers can leverage a declarative approach, cutting-edge features, and a vast ecosystem to bring their immersive web visions to life. If you want to elevate your Vue.js projects with a new dimension, Tres.js is an excellent choice to explore....

Vercel BotID: The Invisible Bot Protection You Needed cover image

Vercel BotID: The Invisible Bot Protection You Needed

Nowadays, bots do not act like “bots”. They can execute JavaScript, solve CAPTCHAs, and navigate as real users. Traditional defenses often fail to meet expectations or frustrate genuine users. That’s why Vercel created BotID, an invisible CAPTCHA that has real-time protections against sophisticated bots that help you protect your critical endpoints. In this blog post, we will explore why you should care about this new tool, how to set it up, its use cases, and some key considerations to take into account. We will be using Next.js for our examples, but please note that this tool is not tied to this framework alone; the only requirement is that your app is deployed and running on Vercel. Why Should You Care? Think about these scenarios: - Checkout flows are overwhelmed by scalpers - Signup forms inundated with fake registrations - API endpoints draining resources with malicious requests They all impact you and your users in a negative way. For example, when bots flood your checkout page, real customers are unable to complete their purchases, resulting in your business losing money and damaging customer trust. Fake signups clutter the app, slowing things down and making user data unreliable. When someone deliberately overloads your app’s API, it can crash or become unusable, making users angry and creating a significant issue for you, the owner. BotID automatically detects and filters bots attempting to perform any of the above actions without interfering with real users. How does it work? A lightweight first-party script quickly gathers a high set of browser & environment signals (this takes ~30ms, really fast so no worry about performance issues), packages them into an opaque token, and sends that token with protected requests via the rewritten challenge/proxy path + header; Vercel’s edge scores it, attaches a verdict, and checkBotId() function simply reads that verdict so your code can allow or block. We will see how this is implemented in a second! But first, let’s get started. Getting Started in Minutes 1. Install the SDK: ` 1. Configure redirects Wrap your next.config.ts with BotID’s helper. This sets up the right rewrites so BotID can do its job (and not get blocked by ad blockers, extensions, etc.): ` 2. Integrate the client on public-facing pages (where BotID runs checks): Declare which routes are protected so BotID can attach special headers when a real user triggers those routes. We need to create instrumentation-client.ts (place it in the root of your application or inside a src folder) and initialize BotID once: ` instrumentation-client.ts runs before the app hydrates, so it’s a perfect place for a global setup! If we have an inferior Next.js version than 15.3, then we would need to use a different approach. We need to render the React component inside the pages or layouts you want to protect, specifying the protected routes: ` 3. Verify requests on your server or API: ` - NOTE: checkBotId() will fail if the route wasn’t listed on the client, because the client is what attaches the special headers that let the edge classify the request! You’re all set - your routes are now protected! In development, checkBotId() function will always return isBot = false so you can build without friction. To disable this, you can override the options for development: ` What happens on a failed check? In our example above, if the check failed, we return a 403, but it is mostly up to you what to do in this case; the most common approaches for this scenario are: - Hard block with a 403 for obviously automated traffic (just what we did in the example above) - Soft fail (generic error/“try again”) when you want to be cautious. - Step-up (require login, email verification, or other business logic). Remember, although rare, false positives can occur, so it’s up to you to determine how you want to balance your fail strategy between security, UX, telemetry, and attacker behavior. checkBotId() So far, we have seen how to use the property isBot from checkBotId(), but there are a few more properties that you can leverage from it. There are: isHuman (boolean): true when BotID classifies the request as a real human session (i.e., a clear “pass”). BotID is designed to return an unambiguous yes/no, so you can gate actions easily. isBot (boolean): We already saw this one. It will be true when the request is classified as automated traffic. isVerifiedBot (boolean): Here comes a less obvious property. Vercel maintains and continuously updates a comprehensive directory of known legitimate bots from across the internet. This directory is regularly updated to include new legitimate services as they emerge. This could be helpful for allowlists or custom logic per bot. We will see an example in a sec. verifiedBotName? (string): The name for the specific verified bot (e.g., “claude-user”). verifiedBotCategory? (string): The type of the verified bot (e.g., “webhook”, “advertising”, “ai_assistant”). bypassed (boolean): it is true if the request skipped BotID check due to a configured Firewall bypass (custom or system). You could use this flag to avoid taking bot-based actions when you’ve explicitly bypassed protection. Handling Verified Bots - NOTE: Handling verified bots is available in botid@1.5.0 and above. It might be the case that you don’t want to block some verified bots because they are not causing damage to you or your users, as it can sometimes be the case for AI-related bots that fetch your site to give information to a user. We can use the properties related to verified bots from checkBotId() to handle these scenarios: ` Choosing your BotID mode When leveraging BotID, you can choose between 2 modes: - Basic Mode: Instant session-based protection, available for all Vercel plans. - Deep Analysis Mode: Enhanced Kasada-powered detection, only available for Pro and Enterprise plan users. Using this mode, you will leverage a more advanced detection and will block the hardest to catch bots To specify the mode you want, you must do so in both the client and the server. This is important because if either of the two does not match, the verification will fail! ` Conclusion Stop chasing bots - let BotID handle them for you! Bots are and will get smarter and more sophisticated. BotID gives you a simple way to push back without slowing your customers down. It is simple to install, customize, and use. Stronger protection equals fewer headaches. Add BotID, ship with confidence, and let the bots trample into a wall without knowing what’s going on....

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co