1import { useEffect, useState } from 'react'; 2 3import { getNativeStateMachineContextAsync } from './Updates'; 4import { addUpdatesStateChangeListener } from './UpdatesEmitter'; 5import type { UseUpdatesReturnType } from './UseUpdates.types'; 6import { 7 currentlyRunning, 8 defaultUseUpdatesState, 9 reduceUpdatesStateFromContext, 10} from './UseUpdatesUtils'; 11import type { UseUpdatesStateType } from './UseUpdatesUtils'; 12 13/** 14 * Hook that obtains information on available updates and on the currently running update. 15 * 16 * @return the structures with information on currently running and available updates. 17 * 18 * @example 19 * ```tsx UpdatesDemo.tsx 20 * import { StatusBar } from 'expo-status-bar'; 21 * import * as Updates from 'expo-updates'; 22 * import React from 'react'; 23 * import { Pressable, Text, View } from 'react-native'; 24 * 25 * export default function UpdatesDemo() { 26 * const { 27 * currentlyRunning, 28 * availableUpdate, 29 * isUpdateAvailable, 30 * isUpdatePending 31 * } = Updates.useUpdates(); 32 * 33 * React.useEffect(() => { 34 * if (isUpdatePending) { 35 * // Update has successfully downloaded 36 * runUpdate(); 37 * } 38 * }, [isUpdatePending]); 39 * 40 * // If true, we show the button to download and run the update 41 * const showDownloadButton = isUpdateAvailable; 42 * 43 * // Show whether or not we are running embedded code or an update 44 * const runTypeMessage = currentlyRunning.isEmbeddedLaunch 45 * ? 'This app is running from built-in code' 46 * : 'This app is running an update'; 47 * 48 * return ( 49 * <View style={styles.container}> 50 * <Text style={styles.headerText}>Updates Demo</Text> 51 * <Text>{runTypeMessage}</Text> 52 * <Button pressHandler={() => Updates.checkForUpdateAsync()} text="Check manually for updates" /> 53 * {showDownloadButton ? ( 54 * <Button pressHandler={() => Updates.fetchUpdateAsync()} text="Download and run update" /> 55 * ) : null} 56 * <StatusBar style="auto" /> 57 * </View> 58 * ); 59 * } 60 * ``` 61 */ 62export const useUpdates: () => UseUpdatesReturnType = () => { 63 const [updatesState, setUpdatesState] = useState<UseUpdatesStateType>(defaultUseUpdatesState); 64 65 // Change the state based on native state machine context changes 66 useEffect(() => { 67 getNativeStateMachineContextAsync() 68 .then((context) => { 69 setUpdatesState((updatesState) => reduceUpdatesStateFromContext(updatesState, context)); 70 }) 71 .catch((error) => { 72 // Native call can fail (e.g. if in development mode), so catch the promise rejection and surface the error 73 setUpdatesState((updatesState) => ({ ...updatesState, initializationError: error })); 74 }); 75 const subscription = addUpdatesStateChangeListener((event) => { 76 setUpdatesState((updatesState) => reduceUpdatesStateFromContext(updatesState, event.context)); 77 }); 78 return () => subscription.remove(); 79 }, []); 80 81 // Return the updates info and the user facing functions 82 return { 83 currentlyRunning, 84 ...updatesState, 85 }; 86}; 87