AppState

AppState.currentState is 'active' in the foreground and 'background' when the user is in another app, on the home screen or, on Android, in another activity such as a system autofill picker; iOS adds 'inactive' for the moment in between. The change event reports transitions, iOS adds memoryWarning, and Android adds blur and focus for moments when the app is visible but not in use, such as a pulled-down notification shade:

src/info/AppStateLog.tsx: every state change and focus event (excerpt)TSX
  const last = useRef(AppState.currentState);
  useEffect(() => {
    const subs = [
      AppState.addEventListener('change', (next) => {
        if (last.current === 'background' && next === 'active') console.log('back in front');
        console.log(`change: ${last.current} -> ${next}`);
        last.current = next;
      }),
      AppState.addEventListener('blur', () => console.log('blur')),    // Android only
      AppState.addEventListener('focus', () => console.log('focus')),  // Android only
    ];
    return () => subs.forEach((s) => s.remove());
  }, []);

Pulling the shade down and up (adb shell cmd statusbar expand-notifications, then collapse), pressing Home and relaunching the app logged:

Output of 79
 LOG  blur
 LOG  focus
 LOG  change: active -> background
 LOG  blur
 LOG  back in front
 LOG  change: background -> active
 LOG  focus

The shade changed only focus. Use change to pause timers and refresh stale data on return, and keep the handler short: the OS may suspend a backgrounded app at any moment.