Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
cpojer opened this issue Feb 15, 2019 · 35 comments
Closed

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

cpojer opened this issue Feb 15, 2019 · 35 comments
Labels
bug Something isn't working

Comments

@cpojer
Copy link
Contributor

cpojer commented Feb 15, 2019


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');
});
@joshjhargreaves
Copy link

joshjhargreaves commented Feb 27, 2019

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.

@retyui
Copy link
Contributor

retyui commented Mar 11, 2019

@krizzu
Copy link
Member

krizzu commented Mar 11, 2019

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?

@mccordgh
Copy link

mccordgh commented Mar 21, 2019

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.

@krizzu
Copy link
Member

krizzu commented Apr 7, 2019

Right,

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

#53 Is PR to help test such cases.

@mccordgh Hey,

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

thanks.

@mccordgh
Copy link

mccordgh commented Apr 8, 2019

@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.

@krizzu krizzu mentioned this issue Apr 10, 2019
@krizzu
Copy link
Member

krizzu commented Apr 11, 2019

v1.3.0 released, please check it out 🙏

@krizzu krizzu closed this as completed Apr 11, 2019
@royisch
Copy link

royisch commented Apr 11, 2019

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

@krizzu krizzu reopened this Apr 11, 2019
@krizzu
Copy link
Member

krizzu commented Apr 11, 2019

@royisch hey,

Can you elaborate bit more? Is in within tests?

@royisch
Copy link

royisch commented Apr 11, 2019

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.

@krizzu
Copy link
Member

krizzu commented Apr 11, 2019

@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?

@royisch
Copy link

royisch commented Apr 11, 2019

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

@royisch
Copy link

royisch commented Apr 11, 2019

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

@krizzu
Copy link
Member

krizzu commented Apr 11, 2019

@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

@royisch
Copy link

royisch commented Apr 14, 2019

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

@krizzu
Copy link
Member

krizzu commented Apr 14, 2019

@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.

@krizzu krizzu closed this as completed Apr 14, 2019
@npedrini
Copy link

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.

@royisch
Copy link

royisch commented Apr 17, 2019

@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.

@never00miss
Copy link

never00miss commented May 14, 2019

@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

@peterleilei86
Copy link

@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

@willdady
Copy link

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.

@willdady
Copy link

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

@MakhouT
Copy link

MakhouT commented Jul 30, 2019

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

@eightyfive
Copy link

@MakhouT facebook/react-native#18372 (comment) 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.

@krizzu
Copy link
Member

krizzu commented Aug 1, 2019

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

@MakhouT
Copy link

MakhouT commented Aug 1, 2019

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!

@jounii
Copy link

jounii commented Aug 9, 2019

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.

@jckw
Copy link

jckw commented Aug 28, 2019

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.

@Cellule
Copy link

Cellule commented Aug 28, 2019

@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.

@krizzu
Copy link
Member

krizzu commented Aug 29, 2019

@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.

@jckw
Copy link

jckw commented Aug 29, 2019

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!

@b3hz4d
Copy link

b3hz4d commented Sep 19, 2019

@EdwardMcConnell
Copy link

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

@amirping
Copy link

I have the same issue in production for some android device, it looks odd that it works on some and on others not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests