Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native - Observe AsyncStorage value changes?

Is there a way to subscribe to an AsyncStorage value changes? I have a setting in one place which is saved in AsyncStorage in an app, which affects every other screen. I need to observe the value so that it is possible to update all the screens. I tried the getValue method but it seems to only get a value initially, and does not update on a change.

like image 350
Simon Moshenko Avatar asked Aug 12 '26 15:08

Simon Moshenko


1 Answers

I solved this issue in my app by building a React Context that synced to AsyncStorage.

In your case, you could have one item called for example appSettings. This would be a stringified JSON object that holds all of your app settings.

const AppSettingsContext = React.createContext({})

const AppSettingsContextProvider = ({children}) => {
  const [appSettingsInitialized, setAppSettingsInitialized] = useState(false)
  const [appSettings, setAppSettings] = useState({}) // could use some default values instead of empty object

  // On mount, get the current value of `appSettings` in AsyncStorage
  useEffect(() => {
    AsyncStorage
      .getItem('appSettings')
      .then(data => {
        // If data is returned, the storage item existed already and we set the appSettings state to that.
        if (data) {
          setAppSettings(JSON.parse(data))
        }
        // If data is null, the appSettings keeps the default value (in this case an empty object)/

        // We set appSettingsInitialized to true to signal that we have successfully retrieved the initial values.
        setAppSettingsInitialized(true)
      })
  }, [])

  // setSettings sets the local state and AsyncStorage
  const setSettings = (key, value) => {
    const mergedSettings = {
      ...appSettings,
      [key]: value
    }
    // First, merge the current state with the new value
    setAppSettings(mergedSettings)

    // Then update the AsyncStorage item
    AsyncStorage.setItem('appSettings', JSON.stringify(mergedSettings))
  }

  return (
    <AppSettingsContext.Provider value={{
      appSettings,
      appSettingsInitialized,
      setSettings,
    }}>
      {children}
    </AppSettingsContext.Provider>
  )
}

(note that this is a pretty basic version, with no error handling)

Then wrap you app in AppSettingsContextProvider

const App = () => (
  <AppSettingsContextProvider>
    {/* Other components */}
  </AppSettingsContextProvider>
)

Then consume the context from any child component:

const SomeChildComponent = () => {
  const { appSettingsInitialized, appSettings } = useContext(AppSettingsContext)

  // For example: wait until initial appSettings have been retrieved AsyncStorage,
  // then use some value that you expect to be present in your business logic.
  // In this case, setAppTheme would set the them color for the whole app, using a
  // `theme` setting saved by the user.
  useEffect(() => {
    if (appSettingsInitialized) {
      setAppTheme(appSettings.theme)
    }
  }, [appSettingsInitialized])

  // Update settings like this for example
  const updateThemeSetting = (newThemeValue) => {
    setSettings('theme', newThemeValue) // eg 'dark', 'light', etc
  }
}
like image 60
samzmann Avatar answered Aug 14 '26 06:08

samzmann