The AsyncStorage API works the same on both the iOS and Android platforms. You would use this API for applications that don't require any network connectivity in the first place, or to store data that's eventually synchronized using an API endpoint once a network becomes available.
Let's look at some code that allows the user to enter a key and a value, and then stores them:
import React, { Component } from 'react';
import {
Text,
TextInput,
View,
FlatList,
AsyncStorage
} from 'react-native';
import { fromJS } from 'immutable';
import styles from './styles';
import Button from './Button';
export default class StoringData extends Component {
// The initial state of this component
// consists of the current "key" and "value"
// that the user is entering. It also has
// a "source" for the list view to display
// everything that's been stored.
state = {
data: fromJS({
key: null,
value: null,
source: []
})
};
// Getter for "Immutable.js" state data...
get data() {
return this.state.data;
}
// Setter for "Immutable.js" state data...
set data(data) {
this.setState({ data });
}
// Uses "AsyncStorage.setItem()" to store
// the current "key" and "value" states.
// When this completes, we can delete
// "key" and "value" and reload the item list.
setItem = () =>
AsyncStorage.setItem(this.data.get('key'), this.data.get('value'))
.then(() => {
this.data = this.data.delete('key').delete('value');
})
.then(() => this.loadItems());
// Uses "AsyncStorage.clear()" to empty any stored
// values. Then, it loads the empty list of
// items to clear the item list on the screen.
clearItems = () =>
AsyncStorage.clear().then(() => this.loadItems());
// This method is async because awaits on the
// data store keys and values, which are two
// dependent async calls.
async loadItems() {
const keys = await AsyncStorage.getAllKeys();
const values = await AsyncStorage.multiGet(keys);
this.data = this.data.set('source', fromJS(values));
}
// Load any existing items that have
// already been stored when the app starts.
componentDidMount() {
this.loadItems();
}
render() {
// The state that we need...
const { source, key, value } = this.data.toJS();
return (
<View style={styles.container}>
<Text>Key:</Text>
<TextInput
style={styles.input}
value={key}
onChangeText={v => {
this.data = this.data.set('key', v);
}}
/>
<Text>Value:</Text>
<TextInput
style={styles.input}
value={value}
onChangeText={v => {
this.data = this.data.set('value', v);
}}
/>
<View style={styles.controls}>
<Button label="Add" onPress={this.setItem} />
<Button label="Clear" onPress={this.clearItems} />
</View>
<View style={styles.list}>
<FlatList
data={source.map(([key, value]) => ({
key: key.toString(),
value
}))}
renderItem={({ item: { value, key } }) => (
<Text>
{value} ({key})
</Text>
)}
/>
</View>
</View>
);
}
}
Before I walk through what this code is doing, let's first take a look at the following screen, since it'll provide most of the explanation you need:

As you can see, there are two input fields and two buttons. The fields allow the user to enter a new key and value. The Add button allows the user to store this key-value pair locally on their device, while the Clear button clears any existing items that have been stored previously.
The AsyncStorage API works the same for both iOS and Android. Under the hood, AsyncStorage works very differently depending on which platform it's running on. The reason React Native is able to expose the same storage API on both platforms is due to its simplicity—it's just key-value pairs. Anything more complex than that is left up to the application developer.
The abstractions that you've created around AsyncStorage in this example are minimal. The idea is to set and get items. However, even straightforward actions like this deserve an abstraction layer. For example, the setItem() method you've implemented here will make the asynchronous call to AsyncStorage and update the items state once that has completed. Loading items is even more complicated because you need to get the keys and values as two separate asynchronous operations.
The reason is to keep the UI responsive. If there are pending screen repaints that need to happen while data is being written to disk, preventing those from happening by blocking them would lead to a sub-optimal user experience.