Async-storage: AsyncStorage.getItem() doesn't seem to work

Created on 15 Feb 2019  路  34Comments  路  Source: react-native-async-storage/async-storage


This issue was originally created by @mrded as facebook/react-native#18372.


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');
});
bug

Most helpful comment

@Krizzu - i still see a reload issue - after reload the storage is not set anymore and returns null. any suggestions?

All 34 comments

We recently saw issues with this in our app on a large number of android devices when doing something very similar to the above in production but we had issues reproducing locally. Very happy to help do the work necessary to fix this. Would be great to use this thread to maybe identify what's causing the issue and different approaches we could use to fix.

Hey @joshjhargreaves @retyui

Thanks for your time.
To dig deeper into the issue, I think we'd need more info about reproducing it - from repro steps, it seems like the problem is happening in a test environment (like @retyui pointed out).

Does the issue exist while developing the app?

I have the same issue, but found a way to make it work with .then().

We have a separate helper class called StorageHelper that has some methods for getting and setting like:

// StorageHelper.js

async function set(key, value) {
  try {
    await AsyncStorage.setItem(key, JSON.stringify(value));
  } catch (error) {
    console.error(error);
    return false;
  }

  return true;
};

async function get(key) {
  try {
    const value = await AsyncStorage.getItem(key);

    return JSON.parse(value);
  } catch (error) {
    console.error(error);
    return null;
  }
};

...

setToken(token) {
    return set('token', token);
},

getToken() {
    return get('token');
},

...

These were working just fine by utilizing them like this:
const token = await Storage.getToken();
and
Storage.setToken(token);

Then, I added a new one. I followed the exact same patterns, just changing the name and all of a sudden this same way of getting the value for this token is returning either a Promise or null when I try:
const token = await Storage.getToken();

The only way I was able to get the value for token and use it in my component was:

constructor(props) {
    super(props);

    this.state = {
      token: null,
    };
  }

  componentDidMount() {
    this.setTokenFromStorage();
  }

  setTokenFromStorage = () => {
    Storage.getToken().then((token) => {
      this.setState({ token });
    });
  }

Not as ideal, but hope it may help someone.

Right,

I believe the original issue came from the fact that there was no Jest mocking function that would actually get values back.

https://github.com/react-native-community/react-native-async-storage/pull/53 Is PR to help test such cases.

@mccordgh Hey,

This looks odd. Could you provide how you implemented getNewOne ?

thanks.

@Krizzu Sorry that may have been confusing to use newOne instead of just using token.

I edited the previous post to change newOne to token, as the implementation would have been the same as the getToken and setToken methods in StorageHelper.js above.

I think it might have just been a misunderstanding on my end as I am very familiar with using a Promise, but wasn't as familiar with async and await.

v1.3.0 released, please check it out 馃檹

@Krizzu - i still see a reload issue - after reload the storage is not set anymore and returns null. any suggestions?

@royisch hey,

Can you elaborate bit more? Is in within tests?

yes. I set using asyncStorage.set, for testing purposes i verified that the data is persisted, so i fetch it back - all looks good. When i reload the same key i get null.
In general for my use-case - you authenticate and go in. when you reload you see the login screen again.

My question is - should i revert to react-native implementation for now? as my application is waiting to be released.

@royisch
There's no such API as asyncStorage.set. Can you show me some code?

Also, did you clean packager's cache, reinstalled the app/linked module properly?

Hi @Krizzu i mean await asyncStorage.setItem. i will try to clear cache and report back

hi @Krizzu i cleaned the cache also.

Im using RN 0.59 and installed "@react-native-community/async-storage": "^1.3.0",

Not sure what the next step is here. Thanks

@royisch
Can you show me the code you use?

Additional steps to consider:

  1. Run packager with cleaned cached: add --resetCache flag when starting
  2. Link it: react-native link @react-native-community/async-storage
  3. Reinstall app: react-native run-android or react-native run-ios

Or remove node_modules and start over

Hi @Krizzu, did all of it, not sure what the next step is. I will try to completely re-install the library again.
Also, to notice, im using redux-persist (offline support) , it is also using asyncStorage, maybe something there collides

@royisch I believe that something in your implementation is causing to (maybe) override values in Async Storage (or calling .clear in startup.).

I'm closing this issue, if you'll need more help, please open new issue with provided repro steps.

thanks.

For what it's worth, I'm seeing similar behavior, where a value I set is null upon refreshing the app. I'm also using redux-offline, which uses redux-persist underneath the hood. I'm wondering if there is some kind of collision when both this newer version of the package and the older one are used at the same time.

@npedrini - i think i have a solution, you can pass as a configuration to redux-offline the storage you want to use, probably you should import the storage from the new AsyncStorage and pass it as a parameter.

@royisch what you mean by new AsyncStorage? From 'react-native' or from '@react-native-community/async-storage'?

My case is same as @npedrini, after apps reload or close, their is doesn't have data back and returned null

@never00miss I can confirm that passing AsyncStorage as a param to redux-offline's persistOptions solved this issue. You can take a look at redux-persist config

I get a similar issue as @npedrini above. I also use redux-persist and I recently reverted it to using the RN version as I was having issues with this library not correctly rehydrating the state. I was also using _this_ library in a separate part of the code and noticed it was always returning null. Reverting that code to use the RN core version also fixed the issue.

I've just tried updating all occurrences of AsyncStorage to the RNC version 1.5.1 and it seems to be working now.

Actually 1.5.1 does not fix the issue. I'll be reverting to using AsyncStorage from RN core.

Having the same issue. Why is this closed? I am on react-native version 0.59.10 and on version 1.5.1 of asynch storage

@MakhouT https://github.com/facebook/react-native/issues/18372#issuecomment-462214891 might help (if you have control over the AsyncStorage code in your project).

the solution (at least for me) is: not to use await in setItem.

@willdady @MakhouT Can you tell me more about issues you see?

Investigated a bit more, and the issue isn't async-storage issue. It was react-native-debugger that doesn't instantly show the result when saving an item. I had to refresh the app to see the item in the debugger. Works as expected currently.
Thanks and sorry for the confusion!

Just a bit related or unrelated, I was investigating similar problem. The await was hanging at the AsyncStorage. However debugging more, revealed it was hanging on any Promise at application startup. ASyncStorage just seemed to be one of the first during init.

Now the problem was then narrowed down to completely different package (in this case it was @storybook/react-native). Reason for the hang is still mystery, but I suspect it is related somehow incompatible React Native versions being used in two different packages and causing some strange internal conflict which does not show up other than hanging Promises.

Lesson learned, make sure packages are compatible. Also some init code should be run after the React Native has initialized itself, so either use useEffect in your App component or use AppRegistry to time the initialization code instead of running it in the import file's root.

I'm still encountering this issue.

I set a token after logging in, and can access it after it's been set:

async function setToken(token) {
  await AsyncStorage.setItem(AppConfig.TOKEN_STORAGE_KEY, token)

  const t = await AsyncStorage.getItem(AppConfig.TOKEN_STORAGE_KEY)
  console.log(t)
}

After reloading the app, await AsyncStorage.getItem(AppConfig.TOKEN_STORAGE_KEY) returns null.

Not using await in the setToken function also doesn't help.

I'm using React Native v0.59.5 and @react-native-community/async-storage v1.3.3.

@jckw We are experiencing similar issue in our app. We haven't been able to reproduce the error ourselves, but we have customers from time to time complaining they have to login again (meaning the token was lost).
Telling them to reboot the device seems to fix the problem on future login.
We tried using react-native-shared-preferences instead with no luck.

@Cellule @jckw Can you see a yellow box warning about AsyncStorage being deprecated? If yes, then there's a condition race happening between Community's and Core AsyncStorage.

They're working on the same files/preferences and the way they do might cause the issue you have. Please refer to my comment about it in another issue.

Ah amazing! Had to patch a few packages we're using that used the old version of AsyncStorage, but now that warning it gone and it seems to have solved the issue.

Thank you!

On Android, I had the issue where AsyncStorage.setItem and getItem worked within the same emulator load, but reloading from the dev menu on the emulator resulted in null answers for all storage data. This fix worked for me. Add AsyncStorage_dedicatedExecutor=true to android/gradle.properties and rebuild.

Updated link: https://react-native-community.github.io/async-storage/docs/advanced/executor

Was this page helpful?
0 / 5 - 0 ratings

Related issues

josmithua picture josmithua  路  20Comments

alex-mironov picture alex-mironov  路  71Comments

santhanakrishnanstark picture santhanakrishnanstark  路  67Comments

burhanahmed92 picture burhanahmed92  路  27Comments

muhammadn picture muhammadn  路  58Comments