react-nativeasyncstorage

Why string saved on AsyncStorage will be retrieved as garbage value?


I'm trying to understand how AsyncStorage works Consider a screen to configure default language:

    // Selected radio button value
    const [value, setValue] = React.useState('first');
    
    // Default lang 
    const [defaultLang, setDefaultLang] = useState('');
      
    const handleButtonClick = () => {
        if (value === 'first'){
                Toast.show({
                    type: 'error',
                    text1: 'Please pick a language!',
                }); 
        } else {
            console.log("Saved language: "+value);
            setAppDefaultLanguage();
        }
    };
    
    async function setAppDefaultLang() {
        return AsyncStorage.setItem('APP_DEFAULT_LANG',value);
    };
    
    async function getAppDefaultLang(){
        const lang = await AsyncStorage.getItem('APP_DEFAULT_LANG') as string;
        setDefaultLang(lang);
        return lang;   
    }
    
     useEffect(() => {
            // Print saved default lang
            const appLang = getAppDefaultLang();
            console.log("dbg: "+JSON.stringify(appLang));
            console.log("Default lang: "+appLang);
      });

Say the value is lang_en. After handleButtonClick is invoked, this line will be printed on log:

Saved language: lang_en

OK so far so good. Now dismiss the screen, and re-open the change language screen. On log, I see this:

dbg: {"_h":0,"_i":0,"_j":null,"_k":null}
Default lang: [object Object]

Why is that garbage value printed, instead of lang_en?


Solution

  • The value you are seeing {"_h":0,"_i":0,"_j":null,"_k":null} is a pending, unresolved promise.

    I am assuming that getAppLang invokes AsyncStorage.getItem, so in order to see the actual value, but you have it inside a useEffect hook so your syntax is incorrect const appLang = getAppLang(); you need to await the promise to get resolved.

    You can solve it by calling await getAppDefaultLang() inside an async function in the hook.

    Something like this:

    useEffect(() => {
            const getLanguage = async () => {
                    const appLang = await getAppDefaultLang();
                    console.log("dbg: "+JSON.stringify(appLang));
                    console.log("Default lang: "+appLang);
    
            }
            getLanguage();
    },[]); // ADDING THE DEPENDENCY ARRAY HERE FOR THE USEEFFECT TO RUN ONLY ONCE
    

    Note: I added an empty array as a hook dependency [] so that it doesn't keep re-triggering the hook on render.