diff --git a/README.md b/README.md index 946405c9..a1cf9fcd 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ storeData = async () => { ``` -### Read data +### Read data ```jsx getData = async () => { @@ -54,6 +54,25 @@ getData = async () => { ``` +### useAsyncStorage hook + +React hooks (introduced in 16.8) allow you to use state and async requests without writing a class. For more info on hooks and how to use them, see [hooks documentation](https://reactjs.org/docs/hooks-intro.html) or the [hooks example](docs/Hooks.md) in this repo. + +`useAsyncStorage` has no hard-coded dependencies in react hooks, it is just a convenience wrapper around `AsyncStorage`. + +```js +import { useAsyncStorage } from '@react-native-community/async-storage'; +``` + +```jsx +const { + getItem, + setItem, + mergeItem, + removeItem +} = useAsyncStorage('@storage_key'); +``` + See docs for [api and more examples.](docs/API.md) ## License diff --git a/babel.config.js b/babel.config.js index 10c6c10e..b3bd9654 100644 --- a/babel.config.js +++ b/babel.config.js @@ -5,7 +5,7 @@ module.exports = { 'module-resolver', { alias: { - '@react-native-community/async-storage': './lib/AsyncStorage', + '@react-native-community/async-storage': './lib/index', }, cwd: 'babelrc', }, diff --git a/docs/API.md b/docs/API.md index b3d177a1..8176fb4c 100644 --- a/docs/API.md +++ b/docs/API.md @@ -13,6 +13,7 @@ - [multiRemove](#multiRemove) - [clear](#clear) - [flushGetRequests](#flushGetRequests) + - [useAsyncStorage](#useAsyncStorage) <br /> @@ -28,7 +29,7 @@ Fetches a data for a given `key`, invokes (optional) callback once completed. static getItem(key: string, [callback]: ?(error: ?Error, result: ?string) => void): Promise ``` -**Returns**: +**Returns**: `Promise` with data, if exists, `null` otherwise. @@ -44,7 +45,7 @@ getMyValue = async () => { } console.log('Done'.) - + } ``` @@ -78,7 +79,7 @@ setValue = async () => { } catch(e) { // save error } - + console.log('Done.') } ``` @@ -181,7 +182,7 @@ removeValue = async () => { } catch(e) { // remove error } - + console.log('Done.') } ``` @@ -260,7 +261,7 @@ getMultiple = async () => { // read error } console.log(values) - + // example console.log output: // [ ['@MyApp_user', 'myUserValue'], ['@MyApp_key', 'myKeyValue'] ] } @@ -299,7 +300,7 @@ multiSet = async () => { } catch(e) { //save error } - + console.log("Done.") } @@ -372,31 +373,31 @@ mergeMultiple = async () => { } catch(e) { // error } - + console.log(currentlyMerged) // console.log output: - // [ - // [ + // [ + // [ // 'USER_1', - // { + // { // name:"Tom", // age:30, - // traits: { - // hair: 'brown' + // traits: { + // hair: 'brown' // eyes: 'blue' // } // } // ], - // [ + // [ // 'USER_2', - // { + // { // name:'Sarah', // age:26, // traits: { - // hair: 'green' + // hair: 'green' // } // } - // ] + // ] // ] } @@ -432,10 +433,10 @@ removeFew = async () => { } catch(e) { // remove error } - + console.log('Done') } - + ``` @@ -467,7 +468,7 @@ clearAll = async () => { } catch(e) { // clear error } - + console.log('Done.') } @@ -493,4 +494,89 @@ static flushGetRequests(): void **Returns**: -`undefined` \ No newline at end of file +`undefined` + + +<!-- ------------------------ HOOKS ------------------------ --> + + +## `useAsyncStorage` + +Uses the new [hooks api](https://reactjs.org/docs/hooks-intro.html) to give you convenience functions so you can get, set, merge and delete a value for a given key from Async Storage. + +The `useAsyncStorage` returns an object that exposes all methods that allow you to interact with the stored value. + +**Signature**: + +```js +static useAsyncStorage(key: string): { + getItem: ( + callback?: ?(error: ?Error, result: string | null) => void, + ) => Promise<string | null>, + setItem: ( + value: string, + callback?: ?(error: ?Error) => void, + ) => Promise<null>, + mergeItem: ( + value: string, + callback?: ?(error: ?Error) => void, + ) => Promise<null>, + removeItem: (callback?: ?(error: ?Error) => void) => Promise<null>, +} +``` + +**Returns**: + +`object` + +**Specific Example**: + +You can replace your `App.js` with the following to see it in action. + +```jsx +import React, { useState, useEffect } from 'react'; +import { View, Text, TouchableOpacity } from 'react-native'; +import { useAsyncStorage } from '@react-native-community/async-storage'; + +export default function App() { + const [value, setValue] = useState('value'); + const { getItem, setItem } = useAsyncStorage('@storage_key'); + + const readItemFromStorage = async () => { + const item = await getItem(); + setValue(item); + }; + + const writeItemToStorage = async newValue => { + await setItem(newValue); + setValue(newValue); + }; + + useEffect(() => { + readItemFromStorage(); + }, []); + + return ( + <View style={{ margin: 40 }}> + <Text>Current value: {value}</Text> + <TouchableOpacity + onPress={() => + writeItemToStorage( + Math.random() + .toString(36) + .substr(2, 5) + ) + } + > + <Text>Update value</Text> + </TouchableOpacity> + </View> + ); +} +``` + +In this example: + +1. On mount, we read the value at `@storage_key` and save it to the state under `value` +2. When pressing on "update value", a new string gets generated, saved to async storage, and to the component state +3. Try to reload your app - you'll see that the last value is still being read from async storage diff --git a/lib/AsyncStorage.js b/lib/AsyncStorage.js index 21a75bbc..47690974 100644 --- a/lib/AsyncStorage.js +++ b/lib/AsyncStorage.js @@ -367,4 +367,4 @@ function convertError(error): ?Error { return out; } -module.exports = AsyncStorage; +export default AsyncStorage; diff --git a/lib/hooks.js b/lib/hooks.js new file mode 100644 index 00000000..1ce9b910 --- /dev/null +++ b/lib/hooks.js @@ -0,0 +1,25 @@ +import AsyncStorage from './AsyncStorage'; + +type AsyncStorageHook = { + getItem: ( + callback?: ?(error: ?Error, result: string | null) => void, + ) => Promise<string | null>, + setItem: ( + value: string, + callback?: ?(error: ?Error) => void, + ) => Promise<null>, + mergeItem: ( + value: string, + callback?: ?(error: ?Error) => void, + ) => Promise<null>, + removeItem: (callback?: ?(error: ?Error) => void) => Promise<null>, +}; + +export function useAsyncStorage(key: string): AsyncStorageHook { + return { + getItem: (...args) => AsyncStorage.getItem(key, ...args), + setItem: (...args) => AsyncStorage.setItem(key, ...args), + mergeItem: (...args) => AsyncStorage.mergeItem(key, ...args), + removeItem: (...args) => AsyncStorage.removeItem(key, ...args), + }; +} \ No newline at end of file diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 00000000..b1752582 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,2 @@ +export default from './AsyncStorage'; +export { useAsyncStorage } from './hooks'; diff --git a/package.json b/package.json index 97ed0a73..7677e5c4 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@react-native-community/async-storage", "version": "1.0.1", "description": "Asynchronous, persistent, key-value storage system for React Native.", - "main": "lib/AsyncStorage.js", + "main": "lib/index.js", "author": "Krzysztof Borowy <krizzu.dev@gmail.com>", "contributors": [], "homepage": "https://github.com/react-native-community/react-native-async-storage#readme",