useAsyncStorage gancho personalizado con useState hook en React Native

Aug 16 2020

Como sabemos, no podemos usar LocalStorage en React Native. Intento crear un gancho personalizado useAsyncStorage en su lugar, que hace la misma función que el gancho personalizado de LocalStorage en reaccionar para almacenar los datos en el almacenamiento local del dispositivo móvil.

useAsyncStorage.js

import React, { useEffect, useState } from 'react';
import AsyncStorage from '@react-native-community/async-storage';


export default function useAsyncStorage(key, defaultValue) {
  const [storageValue, updateStorageValue] = useState(defaultValue);

  useEffect(() => {
    getStorageValue();
  }, []);

  async function getStorageValue() {
    let value = defaultValue;
    try {
      value = (JSON.parse(await AsyncStorage.getItem(key))) || defaultValue;
    } catch (e) {
      // handle here
    } finally {
      updateStorage(value);
    }
  }

  async function updateStorage(newValue) {
    try {
      await AsyncStorage.setItem(key, JSON.stringify(newValue));
    } catch (e) {
      // handle here
    } finally {
      getStorageValue();
    }
  }

  return [storageValue, updateStorageValue];
}

En App.js importo useAsyncStorage.js y trato de usarlo para almacenar los datos en el almacenamiento local del dispositivo móvil.

import useAsyncStorage from './useAsyncStorage';

Para poner sus iniciales:

const [userLevel, setUserLevel] = useAsyncStorage("userLevel",1)

Para establecer el valor:

 setUserLevel(prevLevel => {
   return prevLevel + 1
 })

Funciona como se esperaba y configura los datos, pero no puede recuperar datos de AsyncStorage después de recargar la aplicación.

¿Alguien podría ayudarme? ¿Hice algo mal en el gancho personalizado useAsyncStorage? ¿Por qué los datos no se almacenan en AsyncStorage?

Respuestas

1 YajanaNRao Aug 16 2020 at 14:53

Esta useAsyncStorageimplementación está funcionando para mí.

function useAsyncStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState();

  async function getStoredItem(key, initialValue) {
    try {
      const item = await AsyncStorage.getItem(key);
      const value = item ? JSON.parse(item) : initialValue;
      setStoredValue(value);
    } catch (error) {
      console.log(error);
    }
  }

  useEffect(() => {
    getStoredItem(key, initialValue);
  }, [key, initialValue]);

  const setValue = async (value) => {
    try {
      const valueToStore =
        value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      await AsyncStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.log(error);
    }
  };

  return [storedValue, setValue];
}

Enlace a la demostración de Snack:

https://snack.expo.io/@yajana/useasyncstorage

Referencia:

https://usehooks.com/useLocalStorage/

Otra implementación similar:

https://github.com/react-native-hooks/async-storage/blob/master/src/index.js

1 Earl Dec 04 2020 at 11:32

Puedes probar este gancho personalizado que hice.

import { useEffect, useState } from 'react'
import AsyncStorage from '@react-native-async-storage/async-storage'

const useAsyncStorage = (key, initialValue) => {
  const [data, setData] = useState(initialValue)
  const [retrivedFromStorage, setRetrievedFromStorage] = useState(false)

  useEffect(() => {
    ;(async () => {
      try {
        const value = await AsyncStorage.getItem(key)
        setData(JSON.parse(value) || initialValue)
        setRetrievedFromStorage(true)
      } catch (error) {
        console.error('useAsyncStorage getItem error:', error)
      }
    })()
  }, [key, initialValue])

  const setNewData = async (value) => {
    try {
      await AsyncStorage.setItem(key, JSON.stringify(value))
      setData(value)
    } catch (error) {
      console.error('useAsyncStorage setItem error:', error)
    }
  }

  return [data, setNewData, retrivedFromStorage]
}
export default useAsyncStorage

También puede utilizar retrivedFromStorage para comprobar si los datos se recuperaron correctamente de AsyncStorage.

Wen Aug 16 2020 at 16:15

Encontré que este funciona para mí.

import { useEffect, useState } from 'react';
import AsyncStorage from '@react-native-community/async-storage';

export default function useAsyncStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(initialValue);
  useEffect(() => {
    AsyncStorage.getItem(key)
      .then(value => {
        if (value === null) return initialValue;
        return JSON.parse(value);
      })
      .then(setStoredValue)
  }, [key, initialValue]);

  const setValue = value => {
    const valueToStore = value instanceof Function ? value(storedValue) : value;
    setStoredValue(valueToStore);
    AsyncStorage.setItem(key, JSON.stringify(valueToStore));
  }

  return [storedValue, setValue];
}

Referencia: https://gist.github.com/msukmanowsky/08a3650223dda8b102d2c9fe94ad5c12