Dependent Queries
You will learn
- How to connect one Query to another
- How to check that dependent Query is stale
- How to add multiple children
- How to add multiple parents
Connections between Queries
Dependent (or serial) Queries depend on previous ones to finish before they can execute. To achieve this, it's as easy as using the connectQuery method.
Let's create two Queries, the second one will require data from the first one:
// Our Query from the previous section
const characterQuery = createQuery({
handler: async ({ id }) => {
const response = await fetch(`https://rickandmortyapi.com/api/character/${id}`);
return response.json();
},
});
// Let's create a Query that extracts data about character's origin,
// originUrl is a part of response of characterQuery
const originQuery = createQuery({
handler: async ({ originUrl }) => {
const response = await fetch(originUrl);
return response.json();
},
});Now, we have to connect these Queries to establish static relationship between them.
import { connectQuery } from '@farfetched/core';
connectQuery({
source: characterQuery,
fn({ result: character }) {
return { params: { originUrl: character.origin.url } };
},
target: originQuery,
});It's done, after every successful execution of characterQuery, originQuery will be executed with the parameters returned by fn in connectQuery.
Stale state
After established connection, it becomes clear that originQuery results are useless right after new characterQuery start. But .$status of the child Query won't change at parent start because loading of the child query is not started yet.
To determine that data in the Query is outdated (e.g. because parent execution is already started), you can use boolean Store .$stale.
The typical flow of statuses changes with two dependent queries
Start of the application
- Parent
characterQuery.$statusis "initial"characterQuery.$staleis false
- Child
originQuery.$statusis "initial"originQuery.$staleis false
- Parent
Call
characterQuery.start({ id: 1 })- Parent
characterQuery.$statusis "pending" 🚨characterQuery.$staleis false
- Child
originQuery.$statusis "initial"originQuery.$staleis true 🚨
- Parent
characterQuerysuccessfully finished execution,originQueryis immediately started with the parameters returned byfninconnectQuery- Parent
characterQuery.$statusis "success"characterQuery.$staleis false
- Child
originQuery.$statusis "pending" 🚨originQuery.$staleis true 🚨
- Parent
originQuerysuccessfully finished execution- Parent
characterQuery.$statusis "success"characterQuery.$staleis false
- Child
originQuery.$statusis "success"originQuery.$staleis false
- Parent
Multiple children
connectQuery accepts an array of children as well. E.g., if we have two Queries that depend on the same data, we can connect them to parent in one call:
connectQuery({
source: characterQuery,
fn({ result: character }) {
return { params: { originUrl: character.origin.url } };
},
target: [originQuery, originDetailsQuery],
});INFO
All children Queries have to have the same parameters in this form.
Multiple parents
connectQuery accepts an object with any amount of named parents as well.
connectQuery({
source: { character: characterQuery, language: languageQuery },
fn({ character, language }) {
return {
params: {
originUrl: character.result.origin.url,
language: language.result,
},
};
},
target: originQuery,
});Behavior of this form is pretty simple — children Queries will be started with the parameters returned by fn in connectQuery right after all parents are successfully finished. After first execution, re-execution of any parent will trigger re-execution of all children.
Simplified form
Sometimes, children Queries don't need any parameters. In this case, you can use simplified form of connectQuery:
connectQuery({
source: characterQuery,
target: originQuery,
});