Using react-query to Manage Server Data and Cache with Tanner Linsley

InstructorJoel Hooks

Share this video with your friends

Send Tweet

Joel and Tanner Linsley chatted about why state management is such a big issue when building UI's, the motivation for creating state management tools, how server State has inherently different problems from UI state and therefore needs to be managed differently. Additionally, Tanner gave a walkthrough of how React Query manages query caching and uses a serializable array or "query key" to do this.

Why is state management is such a big issue when building UI's?

  • It gets difficult because of how the DOM works (having immutable nodes).
  • Part of this is why React came to be (to make everything declarative).
  • But it's important to note that State Management was a problem before React.
  • The constant battle of state management has been: "Is this actually what the user is seeing?"
  • Drawbacks of losing State:
    • Users lose trust (for a regular user, it's confusing and frustrating).
    • For developers: they lose trust in their code.
  • The internet has lagged when it comes to managing State.
    • State machines have existed for a long time, and as a community, we are still learning what's the best approach to managing State.

What's the motivation for creating your own tools?

  • Creating open-source software.

  • This blog expands more on the motivation of working on open-source software. ⤵️ https://tannerlinsley.com/blog/the-similarities-between-open-source-work-and-running-a-tech-startup

  • Finding the right tools! An example of this is building React Table.

  • #TanStack

When it comes to State management, what are the big ideas?

  • David Khourshid's works have been a great inspiration!
    • The concept of having State Machines they are sound and solid:
      • 1. Finite State Machines A finite state machine is a mathematical model of computation that describes the behavior of a system that can be in only one state at any given time.

      • 2. Statecharts Computer scientist David Harel presented this formalism as an extension to state machines in his 1987 paper Statecharts: A Visual Formalism for Complex Systems.

      • 3. Actor Model The actor model is another very old mathematical model of computation that goes well with state machines. It states that everything is an "actor" that can do three things:

        • Receive messages
        • Send messages to other actors
        • Do something with the messages it received (its behavior)
  • It's important to note that the same principles of XState can be applied to other things. Those principles are universal, and the implementation is not.
  • Another big idea is not letting your application be in multiple States.
  • Understanding that State can be derived from mathematics.

Server State vs UI State

What should people be asking of their state management libraries?

There are various categories of state, but every type of state can fall into one of two buckets:

1. Server Cache - State's stored on the server, and we store in the client for quick-access (like user data).

2. UI State - State that's only useful in the UI for controlling the interactive parts of our app (like modal isOpen state).

  • We make a mistake when we combine the two.
  • Server cache has inherently different problems from the UI state and therefore needs to be managed differently.
  • If you embrace the fact that what you have is not actually state at all but is instead a cache of state, then you can start thinking about it correctly and therefore managing it correctly.
  • Stop colocating your server-state with your client state.

UI Abstraction

  • For client state: there's no need to go outside of React. Unless I want to, like going for Redux because of the dev tools.
  • For server-state: I'm going to reach for React Query, Apollo, SWR.
  • Keeping track of the local state is easy; it's predictable. You can control everything inside your application.
  • When you start consuming stuff outside of your app, you are no longer in control. They are reading a Snapchat of an API endpoint. People treat data as they own it, which they don't. And that's hard to keep track of.
  • Rule: Who owns this code?
    • If you can answer this question correctly, then you'll know what tool to use.
  • Part of this conversion is this talk:
    • Custom Hooks in React: The Ultimate UI Abstraction Layer: YouTube Link

Recap:

  • Custom Hooks in React is helpful for much more than just managing the local state and one-dimensional side-effects you see in almost every React Hooks example.

  • They can be used to build sophisticated memoization pipelines and chained effects that automatically manage local and network resources.

  • But most importantly, they provide a new layer of abstraction to accomplish new and amazing patterns that we couldn't have just over a year ago.

  • On the surface, this abstraction layer is simply a collection of custom hooks, but when unlocked, it can be the most powerful piece of your application architecture.

Moving away from Redux and Apollo

  • Once we React Hooks came out Tanner moved away from Redux entirely.
    • React Query is significantly different from using Redux. Redux is a global state manager with its own context. React Query to some extent is also a global state manager for async data.
    • If you were to integrate the two, you would move all of your async data out of redux into React Query and only use Redux for non-async-data global application state.
  • A few months, Tanner use Apollo but realized that he didn't like GraphQL.
    • Drawbacks from using Apollo:
      • Force you to manage async data in a synchronous way
      • Duplicate unnecessary network operations
      • Over-engineered caching strategies
  • Tanner asked, how can you get the Apollo experienced without Apollo?

Query Keys in React Query

  • React Query manages query caching for you and uses a serializable array or "query key" to do this.
  • React Query Keys can be strings or an array with a string and then any number of serializable primitives and/or objects, unlike URLs and/or GraphQL query template strings.

Following Query Keys

  • When a query needs more information to describe its data uniquely, you can use an array with a string and many serializable objects to describe it.
  • You can use this query multiple times, using a single cache.
  • You can grab your data from any place. You can pass anything inside the keys, even a graphQL query as long as it resolves data.

Under the hood

  • Query Keys are serialized deterministically.

  • This means that no matter the order of keys in objects, all of the following queries would result in the same final query key.

  • Query keys get passed to the getQueryArgs function and then it determines the arguments by using the queryKey. Utils.js

  • Next, it passes the queryKey to the useBaseQuery function to send it off to buildQuery. useBaseQuery.js

  • Finally, it's passed to the buildQuery. queryCache.js

  • If we take a look at config.js we'll see that the simplest form of a key is not an array, but an individual string. config.js

  • When a query needs more information to describe its data uniquely, you can use an array with a string and any number of serializable objects to describe it.

  • This is where the stableStringify is used.

  • This contains a JSON.stringify function but with a stableStringifyReplacer that will check if any values are objects. If they are Object, it will sort the keys and remap them back.

React Suspense

How come Suspense is integrated into React Query?

  • React Query can be used with React's new Suspense for Data Fetching API's.
  • Since React Query is backed by its own cache, it makes "suspense resilient".
  • No one is using Relay outside of Facebook. Usually, people are not building the next Facebook.
    • Relay feels over-engineered.
  • Joel mentioned that you should optimize for deletion.

"Optimize for deletion when you write your code because if you don't it's easy to end up needing to grind out large rewrites, which contain massive risk."

From Chris Biscardi's Digital Garden: If you can't delete code then you're stuck with it

Adding Suspense to React Query

  • Implementation Suspense to React Query wasn't hard.

  • You can set either the global or query level config's suspense option to true.

  • Its handle by the handleSuspense function. Github

  • People are building the same thing, they are not really worried about changes coming to Suspense.