Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/kingstinct/react-native-healthkit/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The useSubscribeToChanges hook subscribes to changes for a specific HealthKit data type and triggers a callback when new data is added, modified, or deleted. This is useful for keeping your UI in sync with HealthKit data.

Usage

import { useSubscribeToChanges } from '@kingstinct/react-native-healthkit';

useSubscribeToChanges('HKQuantityTypeIdentifierStepCount', (args) => {
  console.log('Steps data changed:', args);
});

Parameters

identifier
SampleTypeIdentifier
required
The HealthKit type identifier to subscribe to (quantity, category, workout, etc.)
onChange
(args: OnChangeCallbackArgs) => void
required
Callback function invoked when data changes
interface OnChangeCallbackArgs {
  typeIdentifier: string;
}

Return Value

This hook does not return a value. It manages the subscription lifecycle automatically, cleaning up when the component unmounts.

Example: Refresh Steps Count

import { useSubscribeToChanges } from '@kingstinct/react-native-healthkit';
import { useState, useCallback } from 'react';
import { View, Text } from 'react-native';
import { getMostRecentQuantitySample } from '@kingstinct/react-native-healthkit';

function StepsCounter() {
  const [steps, setSteps] = useState(0);
  
  const fetchSteps = useCallback(async () => {
    const sample = await getMostRecentQuantitySample(
      'HKQuantityTypeIdentifierStepCount'
    );
    if (sample) {
      setSteps(sample.quantity);
    }
  }, []);
  
  // Subscribe to changes
  useSubscribeToChanges('HKQuantityTypeIdentifierStepCount', () => {
    fetchSteps();
  });
  
  // Initial fetch
  useEffect(() => {
    fetchSteps();
  }, [fetchSteps]);

  return (
    <View>
      <Text style={{ fontSize: 32, fontWeight: 'bold' }}>
        {steps.toLocaleString()}
      </Text>
      <Text>steps</Text>
    </View>
  );
}

Example: Multiple Subscriptions

import { useSubscribeToChanges } from '@kingstinct/react-native-healthkit';
import { useState } from 'react';
import { View, Text } from 'react-native';

function HealthDashboard() {
  const [lastUpdate, setLastUpdate] = useState<{
    type: string;
    time: Date;
  } | null>(null);
  
  const handleChange = (type: string) => () => {
    setLastUpdate({ type, time: new Date() });
    console.log(`${type} data updated`);
  };
  
  // Subscribe to multiple data types
  useSubscribeToChanges(
    'HKQuantityTypeIdentifierStepCount',
    handleChange('Steps')
  );
  
  useSubscribeToChanges(
    'HKQuantityTypeIdentifierHeartRate',
    handleChange('Heart Rate')
  );
  
  useSubscribeToChanges(
    'HKCategoryTypeIdentifierSleepAnalysis',
    handleChange('Sleep')
  );
  
  useSubscribeToChanges(
    'HKWorkoutTypeIdentifier',
    handleChange('Workout')
  );

  return (
    <View style={{ padding: 20 }}>
      <Text style={{ fontSize: 18, fontWeight: 'bold' }}>
        Health Data Monitor
      </Text>
      {lastUpdate && (
        <View style={{ marginTop: 10 }}>
          <Text style={{ color: 'green' }}>
            {lastUpdate.type} updated at {lastUpdate.time.toLocaleTimeString()}
          </Text>
        </View>
      )}
    </View>
  );
}

Example: Refetch Query on Change

import { 
  useSubscribeToChanges,
  queryQuantitySamples 
} from '@kingstinct/react-native-healthkit';
import { useState, useCallback, useEffect } from 'react';
import { View, Text, FlatList } from 'react-native';

function RecentSteps() {
  const [samples, setSamples] = useState([]);
  
  const fetchSamples = useCallback(async () => {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    
    const result = await queryQuantitySamples(
      'HKQuantityTypeIdentifierStepCount',
      {
        filter: { date: { startDate: today } },
        limit: 10,
      }
    );
    
    setSamples(result.samples);
  }, []);
  
  // Refetch when data changes
  useSubscribeToChanges('HKQuantityTypeIdentifierStepCount', fetchSamples);
  
  // Initial fetch
  useEffect(() => {
    fetchSamples();
  }, [fetchSamples]);

  return (
    <View>
      <Text style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 10 }}>
        Recent Steps
      </Text>
      <FlatList
        data={samples}
        keyExtractor={(item) => item.uuid}
        renderItem={({ item }) => (
          <View style={{ padding: 10, borderBottomWidth: 1 }}>
            <Text>{item.quantity} steps</Text>
            <Text style={{ fontSize: 12, color: 'gray' }}>
              {item.startDate.toLocaleString()}
            </Text>
          </View>
        )}
      />
    </View>
  );
}

Example: Live Activity Tracker

import { useSubscribeToChanges } from '@kingstinct/react-native-healthkit';
import { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';

function LiveActivityTracker() {
  const [updateCount, setUpdateCount] = useState(0);
  const [lastUpdateTime, setLastUpdateTime] = useState<Date | null>(null);
  
  useSubscribeToChanges('HKQuantityTypeIdentifierActiveEnergyBurned', () => {
    setUpdateCount((count) => count + 1);
    setLastUpdateTime(new Date());
  });

  return (
    <View style={styles.container}>
      <View style={styles.badge}>
        <Text style={styles.badgeText}>Live</Text>
      </View>
      
      <Text style={styles.title}>Activity Monitor</Text>
      
      <View style={styles.stats}>
        <Text style={styles.label}>Updates Received</Text>
        <Text style={styles.value}>{updateCount}</Text>
      </View>
      
      {lastUpdateTime && (
        <Text style={styles.timestamp}>
          Last update: {lastUpdateTime.toLocaleTimeString()}
        </Text>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 20,
    backgroundColor: '#fff',
    borderRadius: 12,
    position: 'relative',
  },
  badge: {
    position: 'absolute',
    top: 10,
    right: 10,
    backgroundColor: '#ff3b30',
    paddingHorizontal: 8,
    paddingVertical: 4,
    borderRadius: 4,
  },
  badgeText: {
    color: '#fff',
    fontSize: 10,
    fontWeight: 'bold',
  },
  title: {
    fontSize: 20,
    fontWeight: 'bold',
    marginBottom: 15,
  },
  stats: {
    alignItems: 'center',
    marginVertical: 10,
  },
  label: {
    fontSize: 14,
    color: '#666',
  },
  value: {
    fontSize: 32,
    fontWeight: 'bold',
    marginTop: 5,
  },
  timestamp: {
    fontSize: 12,
    color: '#999',
    textAlign: 'center',
    marginTop: 10,
  },
});

Example: Custom Hook with Subscription

import { useSubscribeToChanges } from '@kingstinct/react-native-healthkit';
import { useState, useCallback, useEffect } from 'react';
import { getMostRecentQuantitySample } from '@kingstinct/react-native-healthkit';
import type { QuantityTypeIdentifier, QuantitySample } from '@kingstinct/react-native-healthkit';

// Custom hook that combines subscription with data fetching
function useLiveQuantity(identifier: QuantityTypeIdentifier) {
  const [sample, setSample] = useState<QuantitySample | null>(null);
  const [loading, setLoading] = useState(true);
  
  const fetch = useCallback(async () => {
    try {
      const result = await getMostRecentQuantitySample(identifier);
      setSample(result || null);
    } catch (error) {
      console.error('Failed to fetch sample:', error);
    } finally {
      setLoading(false);
    }
  }, [identifier]);
  
  // Subscribe to changes
  useSubscribeToChanges(identifier, fetch);
  
  // Initial fetch
  useEffect(() => {
    fetch();
  }, [fetch]);
  
  return { sample, loading, refetch: fetch };
}

// Usage
function HeartRateMonitor() {
  const { sample, loading, refetch } = useLiveQuantity(
    'HKQuantityTypeIdentifierHeartRate'
  );
  
  if (loading) return <Text>Loading...</Text>;
  if (!sample) return <Text>No data</Text>;
  
  return (
    <View>
      <Text>{sample.quantity} {sample.unit}</Text>
      <Button title="Refresh" onPress={refetch} />
    </View>
  );
}

Lifecycle Management

The hook automatically:
  • Subscribes when the component mounts
  • Unsubscribes when the component unmounts
  • Updates the subscription if the identifier changes
  • Uses a stable callback reference to avoid unnecessary re-subscriptions

Background Updates

HealthKit can trigger updates even when your app is in the background if you’ve enabled background delivery for specific data types. Configure this separately using HealthKit’s background delivery APIs.

Important Notes

Request authorization first. You must request authorization for the data type before subscribing to changes, or your app may crash.
The callback receives the type identifier, which is useful when using the same callback for multiple subscriptions.

See Also