🐈

React Native の AppState について

2021/06/23に公開

概要

AppState の挙動を知らなかったため不具合に遭遇しました。そんな過去の自分への備忘録です。

useFocusEffect では不十分

私が作っているアプリでは React Navigation を使っています。 アプリがフォアグラウンドに表示されている間だけ web socket を繋ぐ処理を実装しようと思い、 useFocusEffect を使って実装しました。

wrong.js
useFocusEffect(useCallback(() => {
  // 接続処理
  return () => {
    // 切断処理
  };
}, []));

ところが、アプリをバックグラウンドに移行させても 切断処理 が実行されません。

AppState を使おう

アプリがフォアグラウンドに来た(or バックグラウンドに来た)ことをトリガーに処理を実行するには、実は AppState を使う必要がありました。
AppState.currentState で現在の状態が取得でき、 AppState.addEventListener でリスナーを設定することができます。

アプリがフォアグラウンドかつ、画面がフォーカスされた時だけ特定の処理をしたい場合は React Navigation の isFocusedAppState を組み合わせると実現できます。

correct.js

const useIsForeground = () => {
  const [isForeground, setIsForeground] = useState(true);

  useEffect(() => {
    const onChange = (nextAppState: AppStateStatus) => {
      setAppState(nextAppState === "active");
    };
    AppState.addEventListener("change", onChange);
    return () => {
      AppState.removeEventListener("change", onChange);
    };
  }, []);

  return isForeground;
};

const App = () => {
  const isFocused = useIsFocused();
  const isForeground = useIsForeground();
  
  useEffect(() => {
    if (isFocused && isForeground) {
      // 接続処理
      return () => {
        // 切断処理
      };
    }
  }, [isFocused, isForeground]);
};

Discussion