Skip to content
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

useMMKVStorage value persistence #248

Open
dancixx opened this issue May 4, 2022 · 20 comments
Open

useMMKVStorage value persistence #248

dancixx opened this issue May 4, 2022 · 20 comments

Comments

@dancixx
Copy link

dancixx commented May 4, 2022

Describe the bug
When I use the hook to store data on the next app restart I am able to log the prevState but it will be replaced with the defaultValue. I misunderstood the correct usage maybe, or is it a bug maybe?

  1. I create the MMKV instance
  2. Try to store the key-value data
  3. On the next app start I want the run the IF block based on the prev storage value, but got the prevState once, then will be replaced by the defaultValue. Is this normal?

Expected behaviour

export const TeamStyleStorage = new MMKVLoader()
  .withInstanceID('teamStyle')
  .withEncryption()
  .withPersistedDefaultValues()
  .initialize();


const [appIcon, setAppIcon] = useMMKVStorage<string>(
    'appIcon',
    TeamStyleStorage,
    'ic_launcher',
  );

if (
        PLATFORM_IOS &&
        team?.teamStyle?.appIcon &&
        appIcon !== team?.teamStyle?.appIcon
      ) {
        setAppIcon(team?.teamStyle?.appIcon);

        changeIcon(team?.teamStyle?.appIcon);
      } else if (PLATFORM_IOS && !team?.teamStyle?.appIcon) {
        changeIcon('ic_launcher');
      }

Platform Information:

  • OS: iOS 15.4
  • React Native Version 0.67.4
  • Library Version 0.7.2
@ammarahm-ed
Copy link
Owner

ammarahm-ed commented May 5, 2022

@dancixx What is the prevState? Are you saying that the value you stored in storage is replaced by the defaultValue on app restart?

@dancixx
Copy link
Author

dancixx commented May 6, 2022

@ammarahm-ed yes, it is replaced, but If didn't set any defaultValue I got undefined.

@ammarahm-ed
Copy link
Owner

@dancixx I am unable to reproduce this issue.

@dancixx
Copy link
Author

dancixx commented May 7, 2022

@ammarahm-ed I checked again soon. And try to investigate it.

@ammarahm-ed
Copy link
Owner

@dancixx Can you store and read values normally via setString/getString functions without hooks after app restart.

Is default value persisted in storage? yes. Check by clearing app data then calling storage.getString("yourValueKey") after restarting the app.

@dancixx
Copy link
Author

dancixx commented May 7, 2022

@ammarahm-ed when I used the getMap or getMapAsync calls I got method call error so it work with hook only but the persisted value is gone after first render.

@ammarahm-ed
Copy link
Owner

@dancixx Here's the simple example that is working:

const storage = new MMKVStorage.Loader()
  .withEncryption()
  .withPersistedDefaultValues()
  .initialize();
const useStorage = create(storage);

const App = () => {
  const [user, setUser] = useStorage('user', 'robert'); // Default value is "robert"
  console.log(storage.getString('user')); // on rerender value should always be "andrew"

 if (user === "robert") { // Change default username on first launch to andrew
    setUser("andrew");
}

@dancixx
Copy link
Author

dancixx commented May 9, 2022

@ammarahm-ed I tried this, but the default value comes from the backend, so there is a moment where the value is different or undefined. I need a bit more time to check this again.

@ammarahm-ed
Copy link
Owner

@dancixx maybe you can wrap it in a useEffect and update the value in storage once the backend sends the correct value?

@dancixx
Copy link
Author

dancixx commented May 10, 2022

@ammarahm-ed What do you think this normal behaviour or something is bad in my app, so something other causes this issue?

@ammarahm-ed
Copy link
Owner

@dancixx The default value should be there before your component renders. Default values should be used when you know what a possible default value would be before runtime. if you can share the exact code for how you are getting the value from backend etc, I might be able to help you out better.

@dancixx
Copy link
Author

dancixx commented May 11, 2022

@ammarahm-ed I got the persisted value on the first render, but if I set the defaultValue prop, it will be overwritten. Other things, when I leave the defaultValue as empty I get a type error because it is a required arg and the persisted value change to undefined.

1. as first step:
setAppIcon('ic_launcher_non_default')

2. after the app restart
const [appIcon, setAppIcon] = useMMKVStorage<string>(
    'appIcon',
    TeamStyleStorage,
    'ic_launcher',
  );

console.log('result': 'appIcon')
// result: 'ic_launcher_non_default' -> first render
// result: 'ic_launcher' -> after first render

if I use this:
const [appIcon, setAppIcon] = useMMKVStorage<string>(
    'appIcon',
    TeamStyleStorage
  );

console.log('result': 'appIcon')
// result: 'ic_launcher_non_default' -> first render
// result: null or undefined -> after first render
// got type error that defaultValue is required.

@ammarahm-ed
Copy link
Owner

@dancixx Are you calling removeItem in your app some where. Also can you upgrade to v0.7.4 and try again?

@ammarahm-ed
Copy link
Owner

@dancixx I created a simple example to reproduce this:

import {useEffect} from 'react';
import MMKVStorage, {create} from 'react-native-mmkv-storage';

const storage = new MMKVStorage.Loader()
  .withEncryption()
  .withPersistedDefaultValues()
  .initialize();

const useStorage = create(storage);

const App = () => {
  const [appIcon, setAppIcon] = useStorage('appIcon', 'ic_launcher');

  console.log('result: ', appIcon);

  useEffect(() => {
// set appIcon on first launch only
    if (appIcon !== 'ic_launcher_custom') {
      console.log('SETTING APP ICON');
      setAppIcon('ic_launcher_custom');
    }
  }, [appIcon, setAppIcon]);

  return null;
};

export default App;

Does this example correctly demonstrate your use case?

And I could not reproduce the issue with the above example. On app reload/restart value is persisted normally.

I tested this on Android device.
Can you also test on Android device, maybe it's related to iOS only.

@dancixx
Copy link
Author

dancixx commented May 11, 2022

@ammarahm-ed I tested now on iOS and Android too and your example is working fine. I don't know what caused this issue before but I am sure that never called removeItem method. Maybe some expo or react-native settings or whatever.

douugdev added a commit to douugdev/react-native-mmkv-storage that referenced this issue May 14, 2022
useMMKVStorage hook with default values set would store but
not update value when passing falsy params to setNewValue
such as an empty string or the number 0

Refs ammarahm-ed#248
@benjamineruvieru
Copy link

I have a question or rather a complaint.
Why do we always have to hard code a default value before we can use the hooks

Why cant we just use the hooks without setting a default value i.e it would be initialized with the last stored value

@ammarahm-ed
Copy link
Owner

@Benjamin3443 That was fixed in v0.7.5

@benjamineruvieru
Copy link

Can you give me an example on how to use the hook without setting an initial default value, the default value should be what is stored with that key. Thanks

1 similar comment
@benjamineruvieru
Copy link

Can you give me an example on how to use the hook without setting an initial default value, the default value should be what is stored with that key. Thanks

@abdullahIsa
Copy link

Hello, i also noticed i have this issue.

  • when I entered the page where I set data after signing in its all ok and even if I close app and come back data will be ok as long user didn't signout

  • when user wants to signout I call clearMemoryCache() and clearStore() so that the storage will be clean and when user signed in again without closing the app it will have new data but instead its always giving the default although the data has been set on successful authentication but once i restart the app the data shows as should.

solution, for the time being is to use removeItem("user") and any other certain keys i want to remove.

I think clearStore() should be looked into.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants