Skip to content

Offline Support ​

Learn how to implement offline functionality in React Native apps with Flowfull Clients.

Overview ​

@pubflow/react-native includes built-in offline support with:

  • Automatic network detection
  • Mutation queuing when offline
  • Automatic retry when connection is restored
  • Offline indicator component

Network Detection ​

The package automatically detects network status using @react-native-community/netinfo.

Installation ​

bash
npx expo install @react-native-community/netinfo

Offline Indicator ​

Show network status to users:

typescript
import { OfflineIndicator } from '@pubflow/react-native';

function App() {
  return (
    <>
      <OfflineIndicator />
      <YourApp />
    </>
  );
}

The indicator automatically shows when the device is offline.

Mutation Queuing ​

Mutations are automatically queued when offline and executed when connection is restored.

Automatic Queuing ​

typescript
import { useBridgeApi, useBridgeMutation } from '@pubflow/react-native';

function CreatePost() {
  const postService = useBridgeApi({ endpoint: 'posts' });
  const { mutate: createPost, isLoading, queuedMutations } = useBridgeMutation(
    postService,
    'create'
  );
  
  async function handleCreate(data: any) {
    // This will be queued if offline
    await createPost({ data });
  }
  
  return (
    <View>
      <Button title="Create Post" onPress={() => handleCreate({ title: 'New Post' })} />
      {queuedMutations > 0 && (
        <Text>Queued mutations: {queuedMutations}</Text>
      )}
    </View>
  );
}

Queue Status ​

Monitor queued mutations:

typescript
import { useBridgeMutation } from '@pubflow/react-native';

function PostForm() {
  const postService = useBridgeApi({ endpoint: 'posts' });
  const { 
    mutate: createPost, 
    isOffline, 
    queuedMutations 
  } = useBridgeMutation(postService, 'create');
  
  return (
    <View>
      {isOffline && (
        <Text style={{ color: 'orange' }}>
          You are offline. Changes will be synced when connection is restored.
        </Text>
      )}
      {queuedMutations > 0 && (
        <Text>Pending changes: {queuedMutations}</Text>
      )}
    </View>
  );
}

Data Caching ​

Use SWR's caching to show stale data when offline:

typescript
import { useBridgeApi, useBridgeQuery } from '@pubflow/react-native';

function PostList() {
  const postService = useBridgeApi({ endpoint: 'posts' });
  const { data, isLoading, error } = useBridgeQuery(
    postService,
    'list',
    { limit: 20 },
    {
      // SWR config
      revalidateOnFocus: false,
      revalidateOnReconnect: true,
      dedupingInterval: 60000, // 1 minute
    }
  );
  
  if (error && !data) {
    return <Text>Error loading posts</Text>;
  }
  
  // Show cached data even if offline
  return (
    <FlatList
      data={data || []}
      renderItem={({ item }) => <PostItem post={item} />}
    />
  );
}

Optimistic Updates ​

Update UI immediately while mutation is pending:

typescript
import { useState } from 'react';
import { useBridgeApi, useBridgeMutation } from '@pubflow/react-native';

function LikeButton({ postId, initialLikes }: any) {
  const [likes, setLikes] = useState(initialLikes);
  const [isLiked, setIsLiked] = useState(false);
  
  const likeService = useBridgeApi({ endpoint: 'likes' });
  const { mutate: createLike } = useBridgeMutation(likeService, 'create');
  
  async function handleLike() {
    // Optimistic update
    setIsLiked(true);
    setLikes(likes + 1);
    
    try {
      await createLike({ data: { postId } });
    } catch (error) {
      // Revert on error
      setIsLiked(false);
      setLikes(likes);
    }
  }
  
  return (
    <TouchableOpacity onPress={handleLike} disabled={isLiked}>
      <Text>{likes} likes</Text>
    </TouchableOpacity>
  );
}

Pull-to-Refresh ​

Implement pull-to-refresh to manually sync data:

typescript
import { RefreshControl } from 'react-native';
import { useBridgeApi, useBridgeQuery } from '@pubflow/react-native';

function PostList() {
  const postService = useBridgeApi({ endpoint: 'posts' });
  const { data, isLoading, refetch } = useBridgeQuery(
    postService,
    'list',
    { limit: 20 }
  );
  
  return (
    <FlatList
      data={data || []}
      renderItem={({ item }) => <PostItem post={item} />}
      refreshControl={
        <RefreshControl
          refreshing={isLoading}
          onRefresh={refetch}
        />
      }
    />
  );
}

Best Practices ​

  1. Show Offline Status: Always inform users when they're offline
  2. Cache Data: Use SWR caching to show stale data when offline
  3. Queue Mutations: Let mutations queue automatically
  4. Optimistic Updates: Update UI immediately for better UX
  5. Handle Errors: Gracefully handle sync errors
  6. Pull-to-Refresh: Allow manual sync

Limitations ​

  • Only available in @pubflow/react-native
  • Requires @react-native-community/netinfo
  • Queued mutations are lost on app restart (stored in memory)
  • Large queues may impact performance

Next Steps ​