A powerful debugging tool for React Query state and device storage in any React-based application. Whether you're building for mobile, web, desktop, TV, or VR - this package has you covered. It works seamlessly across all platforms where React runs, with zero configuration to disable in production.
Pairs perfectly with React Native DevTools for a complete development experience.
https://github.com/LovesWorking/react-native-react-query-devtools
- π Real-time React Query state synchronization
- πΎ Device storage monitoring with CRUD operations - MMKV, AsyncStorage, and SecureStorage
- π± Works with any React-based framework (React, React Native, Expo, Next.js, etc.)
- π₯οΈ Platform-agnostic: Web, iOS, Android, macOS, Windows, Linux, tvOS, VR - you name it!
- π Socket.IO integration for reliable communication
- π Query status, data, and error monitoring
- β‘οΈ Simple integration with minimal setup
- π§© Perfect companion to React Native DevTools
- π Zero-config production safety - automatically disabled in production builds
# Using npm
npm install --save-dev react-query-external-sync socket.io-client
# Using yarn
yarn add -D react-query-external-sync socket.io-client
# Using pnpm
pnpm add -D react-query-external-sync socket.io-client
Add the hook to your application where you set up your React Query context:
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { useSyncQueriesExternal } from "react-query-external-sync";
import { Platform } from "react-native";
import AsyncStorage from "@react-native-async-storage/async-storage";
import * as SecureStore from "expo-secure-store";
import { storage } from "./mmkv"; // Your MMKV instance
// Create your query client
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<AppContent />
</QueryClientProvider>
);
}
function AppContent() {
// Unified storage queries and external sync - all in one hook!
useSyncQueriesExternal({
queryClient,
socketURL: "http://localhost:42831",
deviceName: Platform.OS,
platform: Platform.OS,
deviceId: Platform.OS,
extraDeviceInfo: {
appVersion: "1.0.0",
},
enableLogs: true,
envVariables: {
NODE_ENV: process.env.NODE_ENV,
},
// Storage monitoring with CRUD operations
mmkvStorage: storage, // MMKV storage for ['#storage', 'mmkv', 'key'] queries + monitoring
asyncStorage: AsyncStorage, // AsyncStorage for ['#storage', 'async', 'key'] queries + monitoring
secureStorage: SecureStore, // SecureStore for ['#storage', 'secure', 'key'] queries + monitoring
secureStorageKeys: [
"userToken",
"refreshToken",
"biometricKey",
"deviceId",
], // SecureStore keys to monitor
});
// Your app content
return <YourApp />;
}
This package is automatically disabled in production builds.
// The package handles this internally:
if (process.env.NODE_ENV !== "production") {
useSyncQueries = require("./new-sync/useSyncQueries").useSyncQueries;
} else {
// In production, this becomes a no-op function
useSyncQueries = () => ({
isConnected: false,
connect: () => {},
disconnect: () => {},
socket: null,
users: [],
});
}
For the best experience, use this package with the React Native DevTools application:
- Download and launch the DevTools application
- Integrate this package in your React application
- Start your application
- DevTools will automatically detect and connect to your running application
Note: For optimal connection, launch DevTools before starting your application.
The useSyncQueriesExternal
hook accepts the following options:
Option | Type | Required | Description |
---|---|---|---|
queryClient |
QueryClient | Yes | Your React Query client instance |
socketURL |
string | Yes | URL of the socket server (e.g., 'http://localhost:42831') |
deviceName |
string | Yes | Human-readable name for your device |
platform |
string | Yes | Platform identifier ('ios', 'android', 'web', 'macos', 'windows', etc.) |
deviceId |
string | Yes | Unique identifier for your device |
extraDeviceInfo |
object | No | Additional device metadata to display in DevTools |
enableLogs |
boolean | No | Enable console logging for debugging (default: false) |
envVariables |
object | No | Environment variables to sync with DevTools |
mmkvStorage |
MmkvStorage | No | MMKV storage instance for real-time monitoring |
asyncStorage |
AsyncStorage | No | AsyncStorage instance for polling-based monitoring |
secureStorage |
SecureStore | No | SecureStore instance for secure data monitoring |
secureStorageKeys |
string[] | No | Array of SecureStore keys to monitor (required if using secureStorage) |
-
DevTools Connection
- Look for "Connected" status in the top-left corner of the DevTools app
- If it shows "Disconnected", restart the DevTools app
-
No Devices Appearing
- Verify the Socket.IO client is installed (
npm list socket.io-client
) - Ensure the hook is properly set up in your app
- Check that
socketURL
matches the DevTools port (default: 42831) - Restart both your app and the DevTools
- Verify the Socket.IO client is installed (
-
Data Not Syncing
- Confirm you're passing the correct
queryClient
instance - Set
enableLogs: true
to see connection information
- Confirm you're passing the correct
That's it! If you're still having issues, visit the GitHub repository for support.
The deviceId
parameter must be persistent across app restarts and re-renders. Using a value that changes (like Date.now()
) will cause each render to be treated as a new device.
Recommended approaches:
// Simple approach for single devices
deviceId: Platform.OS, // Works if you only have one device per platform
// Better approach for multiple simulators/devices of same type
// Using AsyncStorage, MMKV, or another storage solution
const [deviceId, setDeviceId] = useState(Platform.OS);
useEffect(() => {
const loadOrCreateDeviceId = async () => {
// Try to load existing ID
const storedId = await AsyncStorage.getItem('deviceId');
if (storedId) {
setDeviceId(storedId);
} else {
// First launch - generate and store a persistent ID
const newId = `${Platform.OS}-${Date.now()}`;
await AsyncStorage.setItem('deviceId', newId);
setDeviceId(newId);
}
};
loadOrCreateDeviceId();
}, []);
MIT
Made with β€οΈ by LovesWorking