Bookmarkly use cookies to provide analysis of site usage and traffic measurement. Data is collected anonymously. See our Privacy Policy for more information about cookies.

React Query in Web Extensions

| 2 min read

React Query is a library for fetching data from API. Is performant, manages fetched data, and what is the most important is backend agnostic — you can use it with REST or GraphQL APIs. But what about where you didn’t have API at all. Did you ever wonder “Can We use react-query when I don’t have API?”.

Bookmarkly is using it to serve always up-to-date bookmarks in extension. Using ML models helps you organize bookmarks and boost your productivity. It’s totally free!


A scene from Brooklyn 9–9 — great tv show :)

But, how is that possible?

As I mention above react query is backend agnostic. It’s mean it’s not worrying about how we obtain data from the backend. We just need a key that represents our data and the Promise that after resolving fetches our data.

In this example, we are using to add cross-browser support.

import browser from "webextension-polyfill";

export async function getSites() {
const { sites } = await["sites"]);
return sites || [{ id: 1, name: "sample website" }];

In react component, we can use react’s fetch-as-render experimental functionality, that’s why we don’t bother catching errors in the component.

import { getSites } from './queries;

export const Sites = () => {
const { data } = useQuery('sites', getSites);

return (
{ => (
<span key={}>{}</span>

To catch errors we are using error boundaries. We can create a sample component like this:

class ErrorBoundary extends React.Component {
constructor(props) {
this.state = { hasError: false };

static getDerivedStateFromError(error) {
return { hasError: true };

componentDidCatch(error, errorInfo) {
// You can also log the error to an error
// reporting service logErrorToMyService(error, errorInfo);

render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
return this.props.children;
export ErrorBoundary;

Everything is composed like that:

import * as React from "react";
import * as ReactDOM from "react-dom";
import { ReactQueryConfigProvider } from "react-query";
import { Sites } from "./sites";
import { ErrorBoundary } from "./error-boundry";

const queryConfig = {
suspense: true,

async function main(): Promise<Event> {
return new Promise((resolve) =>
window.addEventListener("DOMContentLoaded", resolve)

function render() {
<ReactQueryConfigProvider config={queryConfig}>
<Sites />



As you see, it’s easy to use react query in web extension. React Query has fantastic developer experience. You should try it yourself.