react-native-mmkv-storage
react-native-mmkv-storage copied to clipboard
useMMKVStorage value persistence
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?
- I create the MMKV instance
- Try to store the key-value data
- 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
@dancixx What is the prevState? Are you saying that the value you stored in storage is replaced by the defaultValue on app restart?
@ammarahm-ed yes, it is replaced, but If didn't set any defaultValue I got undefined.
@dancixx I am unable to reproduce this issue.
@ammarahm-ed I checked again soon. And try to investigate it.
@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.
@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.
@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");
}
@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.
@dancixx maybe you can wrap it in a useEffect and update the value in storage once the backend sends the correct value?
@ammarahm-ed What do you think this normal behaviour or something is bad in my app, so something other causes this issue?
@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.
@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.
@dancixx Are you calling removeItem in your app some where. Also can you upgrade to v0.7.4 and try again?
@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.
@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.
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
@Benjamin3443 That was fixed in v0.7.5
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
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
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.