<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged indexeddb</title>
<link>https://coderlegion.com/tag/indexeddb</link>
<description>Powered by Question2Answer</description>
<item>
<title>Build Snappy Offline-First Apps: Introducing SWR and IndexedDB-powered useResource in react-hook-lab</title>
<link>https://coderlegion.com/25269/build-snappy-offline-first-apps-introducing-swr-indexeddb-powered-useresource-react-hook</link>
<description>&lt;p&gt;Data fetching in modern React apps often forces a trade-off: either you build complex caching infrastructure, or you accept awkward layout shifts, loading spinners, and sluggish transitions. SWR (Stale-While-Revalidate) changed the game for in-memory fetching, but what if your app needs to work seamlessly offline, cache gigabytes of data securely, and coordinate state across browser tabs?&lt;/p&gt;
&lt;p&gt;Today, I'm thrilled to announce the release of &lt;strong&gt;useResource&lt;/strong&gt;, a highly optimized React hook designed to tackle SWR-based data fetching, cache persistence, and state management inside the &lt;code&gt;react-hook-lab&lt;/code&gt; library. Along with this, we've updated &lt;strong&gt;useIndexedDB&lt;/strong&gt; with conditional control to lay down a robust architecture for offline-first React systems.&lt;/p&gt;
&lt;p&gt;Let's dive into how it works and how you can use it to build incredibly snappy user interfaces.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;why-useresource-&quot;&gt;Why &lt;code&gt;useResource&lt;/code&gt;?&lt;/h4&gt;
&lt;p&gt;Unlike traditional query libraries that require extensive configuration, &lt;code&gt;useResource&lt;/code&gt; brings atomic SWR caching and browser-native persistence under one simple roof. &lt;/p&gt;
&lt;p&gt;Key features include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Flexible Caching Layers:&lt;/strong&gt; Store cached data in-memory, synchronize it globally across instances using &lt;code&gt;shared&lt;/code&gt; memory, or save it permanently via &lt;code&gt;indexeddb&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optimistic Mutations:&lt;/strong&gt; Update your local UI instantly while the background syncing handles server reconciliations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic Retries:&lt;/strong&gt; Smart exponential backoff retry logic built right into the hook.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tab Synchronization:&lt;/strong&gt; Changes inside one tab automatically replicate in others, minimizing redundant API requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id=&quot;feature-deep-dive-amp-code-examples&quot;&gt;Feature Deep Dive &amp;amp; Code Examples&lt;/h4&gt;
&lt;p&gt;To power these advanced capabilities, we also upgraded &lt;strong&gt;useIndexedDB&lt;/strong&gt; by adding a custom &lt;code&gt;enabled&lt;/code&gt; option. This allows hooks to conditionally bypass storage transactions when they are idle or during complex setup states, avoiding unnecessary database operations.&lt;/p&gt;
&lt;p&gt;Here are two concrete examples showing how you can integrate these updates into your codebase today.&lt;/p&gt;
&lt;h5 id=&quot;example-1-basic-swr-data-fetching&quot;&gt;Example 1: Basic SWR Data Fetching&lt;/h5&gt;
&lt;p&gt;If you need simple background revalidation with robust loading states and easy refresh actions, a lightweight memory cache is all you need.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import React from 'react';
import { useResource } from 'react-hook-lab';

const fetchUserProfile = async (signal) =&amp;gt; {
  const response = await fetch('/api/user/profile', { signal });
  if (!response.ok) throw new Error('Failed to load profile');
  return response.json();
};

export function UserProfile() {
  const { data, loading, error, refresh } = useResource({
    key: 'user-profile',
    fetcher: fetchUserProfile,
    staleTime: 10000, // consider fresh for 10 seconds
  });

  if (loading &amp;amp;&amp;amp; !data) return &amp;lt;p&amp;gt;Loading your profile...&amp;lt;/p&amp;gt;;
  if (error) return &amp;lt;p&amp;gt;Error: {error.message}&amp;lt;/p&amp;gt;;

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h3&amp;gt;Welcome, {data?.name}!&amp;lt;/h3&amp;gt;
      &amp;lt;p&amp;gt;Email: {data?.email}&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={refresh}&amp;gt;Force Revalidate&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;example-2-offline-first-caching-with-indexeddb-amp-optimistic-ui&quot;&gt;Example 2: Offline-First Caching with IndexedDB &amp;amp; Optimistic UI&lt;/h5&gt;
&lt;p&gt;By leveraging the newly integrated IndexedDB storage backend, you can store heavy datasets on the user's hard drive and update the interface immediately while server calls complete in the background.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import React from 'react';
import { useResource } from 'react-hook-lab';

const fetchTodoList = async (signal) =&amp;gt; {
  const response = await fetch('/api/todos', { signal });
  return response.json();
};

export function TodoManager() {
  const { data: todos, mutate, loading } = useResource({
    key: 'todo-items',
    fetcher: fetchTodoList,
    cache: 'indexeddb', // Persist data locally via IndexedDB
    persist: {
      store: 'app-cache-store', 
    },
    initialData: [],
  });

  const handleToggleTodo = (todoId) =&amp;gt; {
    // Optimistically update the checklist locally
    mutate((currentList) =&amp;gt; {
      return (currentList || []).map((todo) =&amp;gt;
        todo.id === todoId ? { ...todo, completed: !todo.completed } : todo
      );
    });
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h2&amp;gt;Your Tasks {loading &amp;amp;&amp;amp; ' (Syncing with server...)'}&amp;lt;/h2&amp;gt;
      &amp;lt;ul&amp;gt;
        {todos?.map((todo) =&amp;gt; (
          &amp;lt;li key={todo.id} style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}&amp;gt;
            &amp;lt;label&amp;gt;
              &amp;lt;input
                type=&quot;checkbox&quot;
                checked={!!todo.completed}
                onChange={() =&amp;gt; handleToggleTodo(todo.id)}
              /&amp;gt;
              {todo.text}
            &amp;lt;/label&amp;gt;
          &amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h4 id=&quot;resources&quot;&gt;Resources&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Saurav-TB-Pandey/react-hook-lab&quot;&gt;https://github.com/Saurav-TB-Pandey/react-hook-lab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NPM Package&lt;/strong&gt;: &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.npmjs.com/package/react-hook-lab&quot;&gt;https://www.npmjs.com/package/react-hook-lab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connect with me on LinkedIn&lt;/strong&gt;: &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.linkedin.com/in/pandeysaurav/&quot;&gt;https://www.linkedin.com/in/pandeysaurav/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Originally published on my blog. You can &lt;a rel=&quot;nofollow&quot; href=&quot;https://sauravtbpandey.blogspot.com/2026/08/case-study-speeding-up-dashboard.html&quot;&gt;read the alternative breakdown here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Originally published on my blog. You can &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/saurav_tb_pandey/build-snappy-offline-first-apps-introducing-swr-and-indexeddb-powered-useresource-in-react-hook-lab-477a&quot;&gt;read the alternative breakdown here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25269/build-snappy-offline-first-apps-introducing-swr-indexeddb-powered-useresource-react-hook</guid>
<pubDate>Thu, 27 Aug 2026 13:31:53 +0000</pubDate>
</item>
</channel>
</rss>