facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
118.9k stars 24.3k forks source link

AsyncStorage.getItem() doesn't seem to work #18372

Closed mrded closed 5 years ago

mrded commented 6 years ago

When I try to set a value via AsyncStorage.getItem(), I cannot request it back.

Environment

Environment: OS: macOS High Sierra 10.13.3 Node: 9.8.0 Yarn: 1.5.1 npm: 5.6.0 Watchman: 4.9.0 Xcode: Xcode 9.2 Build version 9C40b Android Studio: Not Found

Packages: (wanted => installed) react: ^16.3.0-alpha.1 => 16.3.0-alpha.1 react-native: 0.54.0 => 0.54.0

Expected Behavior

await AsyncStorage.setItem('foo', 'bar');
await AsyncStorage.getItem('foo').then(console.log); // 'bar'
await AsyncStorage.getAllKeys().then(console.log); // ['foo']

Actual Behavior

await AsyncStorage.setItem('foo', 'bar');
await AsyncStorage.getItem('foo').then(console.log); // null
await AsyncStorage.getAllKeys().then(console.log); // []

Steps to Reproduce

import { AsyncStorage } from 'react-native';

it('should be able to request a value after it was set', async () => {
  await AsyncStorage.setItem('foo', 'bar');
  const output = await AsyncStorage.getItem('foo');

  expect(output).toBe('bar');
});

it('should be able to see a new key after a value was set', async () => {
  await AsyncStorage.setItem('foo', 'bar');
  const output = await AsyncStorage.getAllKeys();

  expect(output).toContain('foo');
});
RobTS commented 6 years ago

Same here, and literally forever. So I need to close the app on Android and open it again every time I reload -.-

Same was happening with fetch response.json() some time ago, if I remember correctly.

This thing here would solve the problem, but has been stuck for ages: https://github.com/facebook/react-native/pull/18522

However, I am happy to report it seems to work if you run adb kill-server and keep Android Studio shut.

bhanuc commented 6 years ago

Me and my team of 3 RN developers had simultaneously gotten stuck in the same issue, so I wrote a simple FIleSystem based alternative to AsyncStorage named react-native-fs-store module, which is drop-in replacement of asyncStorage for very simple use cases. It also allows automatic switch to actual AsyncStorage in production. I hope it unblocks someone else as well.

crimson-med commented 6 years ago

Same problem here. I do a simple setItem then try a getItem

It just returns:

{
"_40":0,
"_65":0,
"_55":null,
"_72":null,
}

But as mentioned by many people for the maintainers it seems storage isn't important and won't be fixed anytime soon.

I recommend using:

MongoDB SQLite

goughjo02 commented 6 years ago

That's a Promise response. Try getItem(ITEMKEY).then(res => console.log(res)).......... or did you try that?

crimson-med commented 6 years ago

@goughjo02 same as well I tried but sadly my value is never returned hence I have switched to mongo and it works perfect now

4E71-NOP commented 6 years ago

Hmmm i had the same issue.

I tried many different syntaxes you probably got in the previous posts. No success so far. At first i was incline to throw it away. Then i tried less complex (imbrication-wise) syntaxes.

I got there and it finally worked for me.

    async componentDidMount() {
        var AsyncVal = await AsyncStorage.getItem("lchMoteurRch");
        await this.setState({ lchMoteurRch: AsyncVal });
        console.log("ControllerXXX/componentDidMount : state.lchMoteurRch=" + this.state.lchMoteurRch + "; AsyncVal=" + AsyncVal );
    }
// -> ControllerXXX/componentDidMount : state.lchMoteurRch=abcdef; AsyncVal=abcdef

and

    async myfunc(itemValue, itemIndex) { // <- from a Picker
        await AsyncStorage.setItem('lchMoteurRch', itemValue);
        await this.setState({ lchMoteurRch: itemValue }); //shown here if you need to set some state.xxx
        console.log("ControllerXXX/myfunc : index=" + itemIndex + "; val=" + itemValue + "; state.lchMoteurRch=" + this.state.lchMoteurRch)
    }

Version:

with gradle configured like this:

It works in "normal debug" mode and variant=release for me.

Apparently minimizing the callbacks usage probably helped. It may not be that elegant but it's working properly. That's not a bad bargain all things considered.

Now, it raises questions about "this.setState" callback. While debugging i was using the setState callback parameter to log to the console the 'state' object supposedly updated values but with no success.

The asyncStorage value was saved, retrieved and passed properly. I could log it to the console in the 'then' statement. something like : AsyncStorage.setItem('lchMoteurRch', itemValue).then(... ...);

The setState was executing (in a '.then()' statement) but for some reason it did not update the state object. I know the setState method is particular amongst the asynchronous methods. But i wasn't expecting that. Maybe:

I'm left only with question on that. Is it an isolated issue or should we expect different callback behaviors depending on the function used ? Then, where's the doc ???

Well... The solution i found is supposed to do exactly the same. Still... this one worked for me.

sinoridha commented 6 years ago

I face this issue while I run on this condition :

this solution works for me:

  1. Stop remote JS debugging.
  2. close the app on the emulator.
  3. run with react-native run-android
  4. enable remote JS debugging to check the issue.
mezod commented 6 years ago

Experiencing this issue in production with a single AsyncStorage.getItem. Sometimes it works, sometimes it just returns null.

fikrikarim commented 6 years ago

Can we update status of issue? 0.57 is released now, and from the changelog they mentioned AsyncStorage fix. Is the change solve this issue?

Khsed4 commented 6 years ago

Did anyone test 0.57 version ? if it's solved there or no ? they promised that it would be solved.

apcjs commented 6 years ago

@Khsed4, yes I have tested my app on 0.57 and it works fine. I have had the problem with previous versions consistently.

fikrikarim commented 6 years ago

@apcjs, nice. I think we can close this issue now?

kalpeshjjethva commented 6 years ago

you can check this. storage

sagenate24 commented 6 years ago

I had this problem until I removed all console logs in both my asynchronous functions and logger middleware!

silent-tan commented 6 years ago

but in 0.57, can you build your android apk? @apcjs @fikrikarim

apcjs commented 6 years ago

@farzer yes, I'm able to build an APK using 0.57. This was never a problem for me in previous versions. The issue I had was with reading a value from asyncStorage once you reload the app using RR. The promise never got fulfilled. This was consistently failing for me. With 0.57, it works fine.

Also note that I did not upgrade from 0.55.4 to 0.57. I ran react-native init and copied my source code from the old folder. Not sure if that makes a difference.

silent-tan commented 6 years ago

for me, from 0.55 upgrade to 0.57 meet another problem. see #19211

Rana-Muhammad-Amir commented 6 years ago

by converting data to stringify and then setItem ...... and after getting it converting it back work for me .... setting data: AsyncStorage.setItem('saveData', JSON.stringify(value)); getting data: AsyncStorage.getItem('saveData').then((value) => {

    data=JSON.parse(value);

}).done();

worked for me...

sunithakk commented 6 years ago

Hey Guys , I think I found the problem for myself ,it may seems stupid for you but what I did to work is just disable debug JS remotely and without logging my data inside AsyncStorage ,seems it's working every time that I need the data , so the solution for me was to disable Debug JS Remotely on Chrome , then it works perfectly , hopefully it solves other problem .

after build APK again facing same issue. is there any other alternative solution?

TronIsHere commented 6 years ago

0.57.1 not fixed yet...

Khsed4 commented 6 years ago

@sunithakk sorry for my late reply. I was stuck with this stupid problem for almost one week , no way that is suggested in all communities worked for me , but then I found something that is built in with setState() function , which it has a callback function as this website says : https://medium.learnreact.com/setstate-takes-a-callback-1f71ad5d2296. so the only way that I guarantee that it's the only secure way so far is this that u use the setState() function in your promise and everything that you need to run , put them on a function and call it for the setSate() callback function , this is only way you can make sure yourself that you neither get null nor never calling the function . Here I'm going to provide an example for it .

` try {
      AsyncStorage.getItem('firebase_token', (err, item) => {
        if (item) {
          this.setState({
            firebase_token: item,
          }),this.tokenToServer();
        }
      });
      } catch (error) {
      console.log("Error retrieving data" + error);
    }`
wesleyguirra commented 6 years ago

same here

"react": "16.5.0", "react-hot-loader": "^3.1.3", "react-native": "0.57.1",

farzd commented 6 years ago

same problem in expo

  "react-native": "https://github.com/expo/react-native/archive/sdk-30.0.0.tar.gz",
fuj1w4r4 commented 6 years ago

I have upgraded react-native to 0.57. The problem still persist, happen sporadically. and some devices not working. This is very off, and it happens to the production.

cuuupid commented 6 years ago

I have tested this problem thoroughly as I originally thought it was the elusive JS bug where not logging something would cause it to disappear, and I have found that the behaviour of AsyncStorage is random at best.

We have tested on 10 Android devices with different makes and models, all with decent amounts of RAM and free storage space. We also tested with the last 4 iPhones released. Tested with Expo as well as the last 3 versions of React Native.

:ghost: SPOOKY bugs just in time for Halloween!

sandersjj commented 6 years ago

Hello everyone,

Is there a workaround for this issue?

Thanks.

cuuupid commented 6 years ago

@sandersjj try Expo SecureStorage. Alternatively, make sure you eject from expo, and then set and get a very simple standard key when your app loads. For some reason if you can get a full cycle in, it works perfectly (I thin k it has something to do with initializations and failures being blocking on the UI thread, but have no real clue why this works).

wesleyguirra commented 6 years ago

@pshah123 how to use Expo SecureStorage in a native app?

rustan-id commented 6 years ago

Still face the same issue

async componentDidMount() { try { let cities = await AsyncStorage.getItem(key); cities = JSON.parse(cities); this.setState({ cities }); } catch (e) { console.log("error from AsyncStorage: ", e); } }

$ react-native --version react-native-cli: 2.0.1 react-native: 0.57.4

sunithakk commented 6 years ago

@sunithakk sorry for my late reply. I was stuck with this stupid problem for almost one week , no way that is suggested in all communities worked for me , but then I found something that is built in with setState() function , which it has a callback function as this website says : https://medium.learnreact.com/setstate-takes-a-callback-1f71ad5d2296. so the only way that I guarantee that it's the only secure way so far is this that u use the setState() function in your promise and everything that you need to run , put them on a function and call it for the setSate() callback function , this is only way you can make sure yourself that you neither get null nor never calling the function . Here I'm going to provide an example for it .

` try {
      AsyncStorage.getItem('firebase_token', (err, item) => {
        if (item) {
          this.setState({
            firebase_token: item,
          }),this.tokenToServer();
        }
      });
      } catch (error) {
      console.log("Error retrieving data" + error);
    }`

Actually m storing data in separate javascript file. not inside component. pls find below code. AsyncStorage.js


import { AsyncStorage, Text, View, TextInput} from 'react-native'

const LocalStorage = {
  retrieveData : async (value) => {
    try {
      const value = await AsyncStorage.getItem('myKeySpl');
      if (value !== null) {
        return JSON.parse(value);
      }else{
        return false;
      }
     } catch (error) {
      return false; 
     }
  }
}

module.exports = LocalStorage;`
your solution is not working here....
buchidiai commented 5 years ago

i am also experiencing this problem any updates?

cuuupid commented 5 years ago

@pshah123 how to use Expo SecureStorage in a native app?

@wesleyguirra You'll need to use Expo Kit. They've got good docs on everything so it shouldn't be too difficult.

Still face the same issue

async componentDidMount() { try { let cities = await AsyncStorage.getItem(key); cities = JSON.parse(cities); this.setState({ cities }); } catch (e) { console.log("error from AsyncStorage: ", e); } }

$ react-native --version react-native-cli: 2.0.1 react-native: 0.57.4

@rustan-id Even with extremely atomic/simple examples it seems to fail and be random at best 😢

i am also experiencing this problem any updates?

@NativLouie I'm afraid not. I reran my tests today and there hasn't been any change. I will try to implement a native Android/iOS solution and bridge it to RN.

jpost27 commented 5 years ago

I had the same problem with my code hitting AsyncStorage.getItem() and then nothing happening after. Simply enough, it ended up being that I had forgotten to import AsyncStorage. For some reason the app compiled and ran and there was no error message being displayed saying that it didn't recognize what AsyncStorage was.

pascaloliv commented 5 years ago

Hello everyone, same issue here with RN 56.0.

[...]

console.warn('Before user_id')
const user_id = await AsyncStorage.getItem(USER_ID)
console.warn('After user_id')

[...]

App log "Before user_id" and can't go further. It looks like the AsyncStorage promise is never resolved in some case. Which is really blocking. Anyone is using an alternative to AsyncStorage to bypass?

rustan-id commented 5 years ago

i think realm is the best choice.

2018-11-29 23:16 GMT+07.00, Olivier PASCAL notifications@github.com:

Hello everyone, same issue here with RN 56.0.

[...]
console.warn('Before user_id')
const user_id = await AsyncStorage.getItem(USER_ID)
console.warn('After user_id')
[...]

App log "Before user_id" and can't go further. It looks like the AsyncStorage promise is never resolved in some case. Which is really blocking. Anyone using an alternative to AsyncStorage ?

-- You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub: https://github.com/facebook/react-native/issues/18372#issuecomment-442892950

-- Rustan, S.Si.

danfsd commented 5 years ago

To all of those still experiencing the issue, the SecureStore from Expo is a viable alternative, which has APIs signatures very similar to AsyncStorage and already comes bundled with Expo. That solved the issue for me.

programmerElephant commented 5 years ago

i am using AsyncStorage with mobx,but it doesn't work when first launch.here is my code my App.js

    "react-native": "0.57.4",
export default class App extends Component {

  constructor(props) {
    super(props);
  }

  componentDidMount() {
    AsyncStorage.getItem('isFirstOpen')
      .then((value) => {
        let jsonValue = JSON.parse((value));
        if (!jsonValue) {
          let colorMessage = {
            'main': {
              'bgcolor': 'white',
              'recordButtonBg': '#8cc152'
            },
            'leftMain': {
              'bgcolor': 'white',
              'thumeTitle': 'jiben',
              'defaluLanguage': 'xitongyuyan',
              'switchState': false
            },
            'sFont': 'norml'
          }

// when my app first installed,init this config
          AsyncStorage.multiSet(
            [
              ['isFirstOpen', JSON.stringify('yes')],
              ['colorMessage', JSON.stringify(colorMessage)],
              ['languageInfo', JSON.stringify(DeviceInfo.getDeviceLocale())]
            ],
            (error, result) => {
              if (!error) {
                    console.log('already saved')
              }
            });
        } else {
        }
      })
  }
  render() {
    return (
      <Provider rootStore={stores}>
        <RootStack />
      </Provider>
    );
  }
}

my mobx rootStores

class RootStore {

    constructor() {
        this.ageStore = new AgeStore();
        this.colorStore = new BgColor();
    }
}

class BgColor {

    constructor() {
        AsyncStorage.getItem('colorMessage').then(action((data) => {
            this.color = JSON.parse(data);
        }))
    }

    @observable color = ''
    @computed get isHaveColor() {

        return this.color ? this.color : {
            'main': {
                'bgcolor': 'white',
                'recordButtonBg': '#8cc152'
            },
            'leftMain': {
                'bgcolor': 'white',
                'thumeTitle': 'jiben',
                'switchState': false,
                'defaluLanguage':'xitongyuyan'
            },
            'sFont': 'norml'
        };
    }
    @action
    setColor(newColor) {
        this.color = newColor;
    }
}

when i killed my app and launch again(or first launch my app),i can't get my 'colorMessage' from AsyncStorage in this place,any problem with my code? Thanks.

ditorahard commented 5 years ago

I'm also facing the same issue. Is there any update on this or maybe a workaround (other than using expo version) ? Thanks

Sukumar-Abhijeet commented 5 years ago

I also encountered the same issue. I was binding an async function in the UI of one screen. So whenever I was navigating to that screen, the app was getting stuck and restarting the app was not working. It was working only if i restart the expo app and then the project app.

Please check whether an async function is getting invoked on render or not. That could be the issue of AsyncStorage not fetching any item because the previous async has not completed yet. Thanks.

skout90 commented 5 years ago

same issue...... in rn 0.57.8

jclwong commented 5 years ago

This resolved the issue for me. On a related thread: https://github.com/facebook/react-native/issues/14101#issuecomment-345563563

After further investigation: in my case I had an AsyncTask in some Java code (a local web server in my case) that was blocking and hence blocking other AsyncTasks (which AsyncStorage relies on). Setting my AsyncTask to execute in parallel to other tasks (via myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR) instead of myTask.execute()) fixed the issue.

My native Android code had reference to an AsyncTask, which for some reason mucks with AsyncStorage. Once removed it works as intended.

Bradzer commented 5 years ago

Same issue for me. It is such a shame that a such critical and old issue is not being solved.

robertpitt commented 5 years ago

Experiencing the same issue, AsyncStorage is just unusable.

Bradzer commented 5 years ago

@hramos why is the bug report label removed when the issue is not resolved :( It's a really critical issue that needs more attention than it has been given so far

ohasy commented 5 years ago

Hellp all, I have had this issue once too making the app in production go freeze. what a day that was. what worked out for me for temporary solution was instead of getting and setting value from asyncstorage. I used React natie file system (RNFS) and used it as reading and writing file in app reserved root space which is not accessible through file managers, and you're anyway going to store auth tokens here or even you can encrypt/decrypt your stringified json there.

On Tue 16 Oct, 2018, 02:57 Farzad Qasim <notifications@github.com wrote:

same problem in expo

"react-native": "https://github.com/expo/react-native/archive/sdk-30.0.0.tar.gz",

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/facebook/react-native/issues/18372#issuecomment-430018954, or mute the thread https://github.com/notifications/unsubscribe-auth/AKauliyAL9MEA3L6T2GKK6nvC5E5Fa7Jks5ulP2xgaJpZM4SqYil .

Georgge commented 5 years ago

Problem is not getItem, the problem is setItem or that I think. The difference between getItem and setItem is that set not return something (except a null). So, the await of setItem never pass to the next set. Actually, even never set the data.

So, the solution (at least for me) is: not to use await insetItem.

eightyfive commented 5 years ago

At last some valuable information! Thanks @Georgge

AleksandarSavic95 commented 5 years ago

This is still an issue, and the problem is not in using await with setItem. iOS simulator (iPhone X) works perfectly, but on a real iPhone 6 and 8, it fails (storage is empty after going to another screen or reloading). Works well on OnePlus (Android).

cpojer commented 5 years ago

This issue has been moved to react-native-community/react-native-async-storage#12.

chenop commented 5 years ago

To fix the live reload - switching to async await worked for me.

Checked this SO Answer (and vote up :-) )