skip to Main Content

With react-native, AppState component allows to listen if an application is in the foreground (active) or in the background (background).

Its implementation is very simple :

useEffect(() => {
  const appStateListener = AppState.addEventListener('change', appState => {
    if (appState === 'active') {
      console.log('App active')
    } else {
      console.log('App not active')
    }

    // !!!!! no console.log() at application startup, only when changing background/foreground !!!!!

  })

  return () => appStateListener.remove()
}, [])

react-native-mmkv allows to store values locally. It has a listener to detect changes :

useEffect(() => {
  const storageListener = storage.addOnValueChangedListener((changedKey) => {
    const newValue = storage.getString(changedKey)

    console.log(`"${changedKey}" new value: ${newValue}`)
  })

  return () => storageListener.remove()
}, [])

But I don’t know how to use both simultaneously. I would like to activate the react-native-mmkv listener when the application starts (useEffect()) AND when the application is in the foreground.

When the application is closed or in the background, I would like to remove this listener.


I tried this but I know it’s not good, and the application crashes when the application goes from the background to the foreground ("Maximum call stack size exceeded").

useEffect(() => {
  const enableStorageListener = () => {
    return storage.addOnValueChangedListener((changedKey) => {
      //...
    })
  }

  let storageListener = enableStorageListener()

  const appStateListener = AppState.addEventListener('change', appState => {
    if (appState === 'active') {
      storageListener = enableStorageListener()
    } else {
      storageListener.remove()
    }
  })

  return () => {
    appStateListener.remove()
    storageListener.remove()
  }
}, [])

2

Answers


  1. Can you try to keep the AppState in a state

    const [appState, setAppState] = useState("");
    
    useEffect(() => {
      const appStateListener = AppState.addEventListener("change", (appState) => {
        if (appState === "active") {
          setAppState("active");
          console.log("App active");
        } else {
          setAppState("deactive");
          console.log("App not active");
        }
    
        // !!!!! no console.log() at application startup, only when changing background/foreground !!!!!
      });
    
      return () => appStateListener.remove();
    }, []);
    
    useEffect(() => {
      const storageListener = storage.addOnValueChangedListener((changedKey) => {
        if (appState === "active") {
          const newValue = storage.getString(changedKey);
          console.log(`"${changedKey}" new value: ${newValue}`);
        }
      });
    
      return () => storageListener.remove();
    }, []);
    
    Login or Signup to reply.
  2. To use both components, you can combine their listeners within a single useEffect hook, and conditionally enable/disable the storage listener based on the app state:

    useEffect(() => {
      let storageListener = null;
      const enableStorageListener = () => {
        storageListener = storage.addOnValueChangedListener((changedKey) => {
          // ...
        });
      };
      
      const appStateListener = AppState.addEventListener('change', (appState) => {
        if (appState === 'active') {
          enableStorageListener();
        } else if (storageListener) {
          storageListener.remove();
          storageListener = null;
        }
      });
    
      if (AppState.currentState === 'active') {
        enableStorageListener();
      }
    
      return () => {
        appStateListener.remove();
        if (storageListener) {
          storageListener.remove();
        }
      };
    }, []);
    
    

    This way, the storage listener is enabled when the app is active and disabled when it’s in the background. The return statement in the hook is used to cleanup the listeners when the component is unmounted.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search