Error Handling
Queries
There are two ways to handle query errors depending on whether you are using Suspense. If you are using Suspense, wrap your component in an error boundary component. We recommend react-error-boundary. If you are not using Suspense, handle errors directly in the component.
Error Handling with Suspense
Wrap your component in an ErrorBoundary. We recommend using react-error-boundary.
typescript
import React, {Suspense} from 'react';
import {create} from "zustand";
import {hook, effect, query, Query, Effect} from "leo-query";
import {ErrorBoundary} from 'react-error-boundary';
interface DogState {
dogs: Query<DogState, number>;
increasePopulation: Effect<DogState>;
removeAllDogs: Effect<DogState>;
}
const useDogStore = create<DogState>(() => ({
increasePopulation: effect(increasePopulation),
removeAllDogs: effect(removeAllDogs),
dogs: query(fetchDogs, s => [s.increasePopulation, s.removeAllDogs]),
}));
const useDogStoreAsync = hook(useDogStore); //uses suspense by default
function Dogs() {
const dogs = useDogStoreAsync(state => state.dogs);
return <div>Dogs: {dogs}</div>;
}
function App() {
return (
<ErrorBoundary fallback={<div>Error loading dogs</div>}>
<Suspense fallback={<div>Loading...</div>}>
<Dogs />
</Suspense>
</ErrorBoundary>
);
}Error Handling without Suspense
Handle the error in your component with the error property.
typescript
import React from 'react';
import {create} from "zustand";
import {hook, effect, query, Query, Effect} from "leo-query";
interface DogState {
dogs: Query<DogState, number>;
increasePopulation: Effect<DogState>;
removeAllDogs: Effect<DogState>;
}
const useDogStore = create<DogState>(() => ({
increasePopulation: effect(increasePopulation),
removeAllDogs: effect(removeAllDogs),
dogs: query(fetchDogs, s => [s.increasePopulation, s.removeAllDogs]),
}));
const useDogStoreAsync = hook(useDogStore, /*suspense*/false); //uses suspense by default
function Dogs() {
const dogs = useDogStoreAsync(state => state.dogs);
if (dogs.isLoading) {
return <div>Loading...</div>;
}
if (dogs.error) {
return <div>Error loading dogs</div>;
}
return <div>Dogs: {dogs.value}</div>;
}
function App() {
return <Dogs />;
}Effects
Effects provide two properties for error handling: error and errors. The error property contains the error from the most recent trigger if it failed. The errors property contains all errors encountered by the effect.
typescript
import React from 'react';
import {create} from "zustand";
import {hook, effect, query, Query, Effect} from "leo-query";
interface DogState {
dogs: Query<DogState, number>;
increasePopulation: Effect<DogState>;
removeAllDogs: Effect<DogState>;
}
const useDogStore = create<DogState>(() => ({
increasePopulation: effect(increasePopulation),
removeAllDogs: effect(removeAllDogs),
dogs: query(fetchDogs, s => [s.increasePopulation, s.removeAllDogs]),
}));
const useDogStoreAsync = hook(useDogStore, /*suspense*/false); //uses suspense by default
function Dogs() {
const dogs = useDogStoreAsync(state => state.dogs);
if (dogs.isLoading) {
return <div>Loading...</div>;
}
if (dogs.error) {
return <div>Error loading dogs</div>;
}
return <div>Dogs: {dogs.value}</div>;
}
function Controls() {
const increasePopulation = useDogStore(state => state.increasePopulation.trigger);
const error = useDogStore(state => state.increasePopulation.error);
useEffect(() => {
if (error) {
console.error(error);
}
}, [error]);
return <button className="cool-button" onClick={increasePopulation}>one up</button>;
}
function App() {
return (
<>
<Dogs />
<Controls />
</>
);
}