Error Handling
Queries
There are three ways to handle query errors. You can use one or multiple approaches.
- Error Handling with Suspense: If you are using Suspense, wrap your component in an error boundary component. We recommend react-error-boundary.
- Error Handling without Suspense: Handle errors directly in your component with the
error
property. - Global Error Handling: Handle errors at the global level with the events api.
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. Additionally, effect errors can be handled at the global level with the events api.
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 />
</>
);
}
Global Error Handling
Having a global error handler can be useful to display notifications, log errors, etc. You can handle errors globally by using the events api.
Example
typescript
import {events} from "leo-query";
events.addEventListener("error", e => {
const payload = e.detail;
if (payload.query) {
console.error(payload.error, payload.query);
}
if (payload.effect) {
console.error(payload.error, payload.effect);
}
});