When working with React Native, you’ve most likely already used React AsyncStorage
as a storage solution. For example, you can use AsyncStorage
to store key-value pairs, such as your application’s current theme, or even store state and tokens for various reasons.
In addition AsyncStorage
, we can also use some third-party storage solutions. In this article, we’ll look at react-native-mmkv
the library and explore why you might want to use it instead AsyncStorage
, and how to use it in our applications.
Contents
Why use react-native-mmkv?
The react-native-mmkv library developed by WeChat allows us to efficiently store and read key-value pairs from the MMKV storage framework. Its name is memory-map key-value
short for React Native Storage.
Similar to AsyncStorage, react-native-mmkv
it also has cross-platform compatibility, meaning it works on both iOS and Android platforms. Let’s look at some reasons why you might consider using MMKV instead of AsyncStorage
.
encryption
AsyncStorage
It is an unencrypted storage system. AsyncStorage
Storage solutions like are not recommended for storing passwords, tokens, and other private information.
MMKV
More secure than AsyncStorage
, offering data encryption and other more advanced security features. If you want to store sensitive data that requires a high level of security, MMKV is a better choice.
Fully synchronized storage
AsyncStorage
is an asynchronous storage system that utilizes async/await
与promises
. In contrast, react-native-mmkv
all calls to are fully synchronous and can therefore be made without using any promises.
Let’s take a look at the code below for better understanding:
// AsyncStorage // storing data const storeUser = async ( value ) => { try { await AsynStorage . setItem ( "user" , JSON . stringify (value)); } catch (error) { console . log (error); } }; storeUser ( "Chimezie" ) // getting data const getUser = async () => { try { const userData = await AsynStorage . getItem ( "user" ) const user = JSON . parse (userData) } catch (error) { console . log (error); } };
If you look at the code above, you can see that we are using both when storing and retrieving stored data async/await
.
Using react-native-mmkv
, instead of issuing a Promise request, we can call it as follows:
// react-native-mmkv storage.set ( ' username' , 'Chimezie' ); const username = storage.getString( 'username' )
In the example above react-native-mmkv
, we are setting our username into our storage. When we want to retrieve data, we use the getString() method because we are getting string data. react-native-mmkv
Does not AsyncStorage
return one like promise
.
Serialization
If you look at our example above, you’ll notice that we are AsyncStorage
converting the user’s value that we want to store in into a string. This is because AsyncStorage
is dealing with string values, so we have to serialize all non-string data types before saving.
const storeUser = async () => { try { const userData = { name : "Chimezie" , location : "Nigeria" } const serializedUser = JSON . stringify (userData) await AsynStorage . setItem ( "user" , serializedUser); } catch (error) { console . log (error); } };
Likewise, to AsyncStorage
retrieve data using
const getUser = async () => { try { const userData = await AsynStorage . getItem ( "user" ) const userObject = JSON . parse (userData) } catch (error) { console . log (error); } };
For MMKV, this is not the case. In this regard, MMKV is more efficient as it supports different basic types or data types such as booleans, numbers, and strings. Simply put, you don’t need to manually serialize all values before storing them.
storage . set ( 'username' , 'Innocent' ) // string storage . set ( 'age' , 25 ) // number storage . set ( 'is-mmkv-fast-asf' , true ) // boolean
Faster performance
Since react-native-mmkv
non-string data is not serialized and parsed, it is AsyncStorage
faster than . The image below, from the MMKV team, shows benchmark results for the time it takes to read data a thousand times from different storage solutions. MMKV proves to be faster than all other schemes:
Additionally, because MMKV is fully synchronous, it eliminates promise
the stress of waiting for completion to get data. This makes reading and writing data much easier and faster – without having to deal with any promise
or error logic.
Limitations of react-native-mmkv
Although react-native-mmkv
the library has many advantages, it also has some limitations. In this section, we will discuss some things to pay attention to when using MMKV.
debug
MMKV
Utilizing the JavaScript Interface (JSI), it provides synchronous local access to improve efficiency and performance. However, this poses a challenge for remote debugging because tools like Chrome DevTools use the traditional React Native bridge rather than the JSI bridge.
As a workaround for this limitation, you can use the Flipper debugging tool . Flipper is designed for debugging when your application is JSI enabled or your application uses a JSI library like MMKV. Alternatively, you can log your errors to the console for debugging.
memory size
The MMKV library is very efficient for storing small amounts of data such as user preferences, theme status, or application settings. There are no specific size measurements or limits, but MMKV is recommended for storing small data.
However, since it provides in-memory storage, storing large amounts of data will consume memory and hinder application performance. Therefore, it is not recommended to use MMKV to store large amounts of data.
document
Unlike AsyncStorage
, react-native-mmkv
documentation for the library is very limited. The only documentation available is the README.md file in the library’s GitHub repository, which explains how to use the library.
Using react-native-mmkv
We have now seen some of the reasons why you might consider using MMKV instead of AsyncStorage, as well as some of its limitations. In this section, we will look at how to use react-native-mmkv
packages to store and retrieve key-value data in our application .
MMKV does not work in Expo, so you can use it in a bare React Native project, or by pre-building and popping your Expo app. To install the package, run any of the following commands:
// npm npm install react- native -mmkv //yarn yarn add react- native -mmkv
Next, we will create an instance and then initialize it. We can then call this instance anywhere in the application.
Create a Storage.js
file called and copy the code below:
// Storage.js import { MMKV } from 'react-native-mmkv' export const storage = new MMKV ({ id : `user-storage` , path : ` ${USER_DIRECTORY} /storage` , encryptionKey : 'encryptionkey' })
In the above code, we first import the installed package. Next, we create an storage
instance named which can accept three options – id
, path
and encryptionKey
.
id
Is a unique identifier used to distinguish MMKV instances. You can create different instances to store different kinds of data. id
Helps distinguish or separate them:
const passwordStorage = new MMKV({ id: `password-storage`, }) const themeStorage = new MMKV({ id: `theme-storage`, })
path
It is the root file where MMKV stores data on your device. It also allows you to customize the path or directory to your liking.
encryptionKey
is a unique key used to encrypt data before storage and decrypt it after retrieval.
After we create the instance, we can import the instance and use it in any component.
Storing data
As we saw before, MMKV supports different data types, which means we can store different data types without serializing them.
First, let’s import our installed packages:
//App.js import { storage } from './Storage'
Next, we will use storage to store our data:
storage . set ( 'username' , 'Innocent' ) // string storage . set ( 'age' , 25 ) // number storage . set ( 'is-mmkv-fast-asf' , true ) // boolean
That’s it! As you can see in the code comments above, react-native-mmkv
string, numeric, and boolean data types are supported. However, with objects and arrays, we must serialize the data before we can save it.
// objects const user = { name : "Chimezie", location : "Nigeria", email: 'chimezieinnocent39@gmail.com' , } storage . set ("userDetails", JSON .stringify( user )) // arrays const numberArray = [ 1 , 2 , 3 , 4 , 5 ]; const serializedArray = JSON .stringify(numberArray); storage .set ( 'numbers' , serializedArray);
Retrieve data
Retrieving data using MMKV is as simple and straightforward as storing it. You use getString()
to get string data, to getNumber()
get numeric data, and to getBoolean()
get boolean data:
const username = storage.get String(' username ') // 'Innocent' const age = storage.get Number(' age ') // 25 const isMmkvFastAsf = storage.get Boolean(' is - mmkv - fast - asf ') // true
For objects and arrays, we will use getString()
because we serialize it before saving it – in other words, store it as string data. We will then use JSON.parse()
to deserialize or convert back to the original state or data type.
// objects const serializedUser = storage. getString ( 'userDetails' ); const userObject = JSON . parse (serializedUser); console . log (userObject); /* output: const user = { name: "Chimezie", location: "Nigeria", email: 'chimezieinnocent39@gmail.com', } */ // arrays const serializedArray = storage. getString ( 'numbers' ); const numberArray = JSON . parse (serializedArray); console . log (numberArray); // Output: [1, 2, 3, 4, 5]
Additionally, in the case where you want to view all keys in the store, MMKV getAllKeys()
allows us to do this by providing a method called . This method returns an array containing all keys stored in the instance:
// Set some key- value pairs storage . set ( 'name' , 'Innocent' ); storage . set ( 'age' , 25 ); const allKeys = storage .getAllKeys(); console.log(allKeys); // Output: [ 'name' , 'age' ]
delete data
Deleting data using MMKV is similar AsyncStorage
. We can delete specific keys or all keys in our instance:
// delete a key storage.delete ( 'username ' ) // delete all keys storage.clearAll()
Encrypt data
Data encryption is AsyncStorage
another advantage of MMKV compared to . MMKV provides the option to encrypt data before storing it, but AsyncStorage
does not provide encryption functionality.
Before encrypting any data, we must first provide an encryption key in our instance. MMKV uses this key to encrypt and decrypt data:
// Storage.js import { MMKV } from 'react-native-mmkv' export const storage = new MMKV ({ id : `user-storage` , encryptionKey : 'EncrypTedKey123' })
We can then encrypt any data we want like this:
// App.js storage . set ( 'userPassword' , 'This is a secret user password' ); // Retrieving data from the encrypted storage const password = storage .getString( 'userPassword' ); console.log( password ); // Output: 'This is a secret user password
Subscribe to updates
react-native-mmkv
Allows us to subscribe to updates or changes to key-value data. To subscribe to updates, we can addOnValueChangedListener()
register an event listener using the method. Whenever the specified key-value pair data changes, the listener will be notified.
Let’s see how we can do this:
//App.tsx import React , {useState, useEffect} from 'react' ; import { Colors } from 'react-native/Libraries/NewAppScreen' ; import { Text , View , Button , StatusBar , StyleSheet , SafeAreaView , } from 'react-native' ; import {storage} from './Storage' ; function App (): JSX . Element { const [isDarkMode, setIsDarkMode] = useState<boolean>( false ); const backgroundStyle = { backgroundColor : isDarkMode ? Colors . darker : Colors . lighter , }; useEffect ( () => { const listener = storage. addOnValueChangedListener ( changedKey => { if (changedKey === 'isDarkMode' ) { const newValue = storage. getBoolean (changedKey); console . log ( 'theme:' , newValue) ; } }); return () => { listener.remove ( ); }; }, []); const toggleTheme = () => { const newMode = !isDarkMode; setIsDarkMode (newMode); storage.set ( ' isDarkMode ' , newMode); }; return ( < SafeAreaView style = {[backgroundStyle, styles.sectionContainer ]}> < StatusBar barStyle = {isDarkMode ? ' light-content ' : ' dark-content '} backgroundColor = {backgroundStyle.backgroundColor} /> < View > < Text style = {[ styles.sectionTitle , { color: isDarkMode ? Colors.white : Colors.black , }, ]}> {isDarkMode ? 'Dark Mode' : 'Light Theme'} </ Text > < Text style = {[ styles.sectionDescription , { color: isDarkMode ? Colors.light : Colors.dark , }, ]}> React Native MMKV Tutorial </ Text > < Button onPress = {toggleTheme} title = {isDarkMode ? ' Switch to light mode ' : ' Switch to dark mode '} /> </ View > </ SafeAreaView > ); } const styles = StyleSheet . create ({ sectionContainer : { flex : 1 , justifyContent : 'center' , alignItems : 'center' , }, sectionTitle : { fontSize : 24 , fontWeight : '600' , textAlign : 'center' , }, sectionDescription : { marginVertical : 8 , fontSize : 18 , fontWeight : '400' , textAlign : 'center' , }, highlight : { fontWeight : '700' , }, }); export default App ;
In the above code, we use addOnValueChangedListener()
the method to register a callback function. This function listens for changes to a specific key in the MMKV store.
The callback function takes changedKey
as an argument, storage.getBoolean(changedKey)
gets the new value associated with that key, and logs its new value to the console.
Whenever a key-value pair in MMKV is modified, a callback function will be called with the name of the key that was changed, allowing you to react to the change in your application.
Finally, we useEffect
unsubscribe the listener in the return function. This is done to avoid or prevent memory leaks when our component is unloaded.
Summarize
In this article, we explore some of the reasons you might consider using MMKV instead of AsyncStorage and consider some of its limitations. You can check out the code examples we used in this GitLab repository.
It is true that MMKV is newer than AsyncStorage and does not have as broad a community as AsyncStorage. However, MMKV provides a faster, more efficient, and more secure storage system. This library has over 50 contributors and is extremely well maintained.