Skip to content

Commit ef3c092

Browse files
kadikramankrizzu
authored andcommittedFeb 27, 2019
feat: add custom hooks
1 parent 9f1727c commit ef3c092

File tree

7 files changed

+156
-24
lines changed

7 files changed

+156
-24
lines changed
 

‎README.md

+20-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ storeData = async () => {
3838

3939
```
4040

41-
### Read data
41+
### Read data
4242
```jsx
4343

4444
getData = async () => {
@@ -54,6 +54,25 @@ getData = async () => {
5454

5555
```
5656

57+
### useAsyncStorage hook
58+
59+
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.
60+
61+
`useAsyncStorage` has no hard-coded dependencies in react hooks, it is just a convenience wrapper around `AsyncStorage`.
62+
63+
```js
64+
import { useAsyncStorage } from '@react-native-community/async-storage';
65+
```
66+
67+
```jsx
68+
const {
69+
getItem,
70+
setItem,
71+
mergeItem,
72+
removeItem
73+
} = useAsyncStorage('@storage_key');
74+
```
75+
5776
See docs for [api and more examples.](docs/API.md)
5877

5978
## License

‎babel.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module.exports = {
55
'module-resolver',
66
{
77
alias: {
8-
'@react-native-community/async-storage': './lib/AsyncStorage',
8+
'@react-native-community/async-storage': './lib/index',
99
},
1010
cwd: 'babelrc',
1111
},

‎docs/API.md

+106-20
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- [multiRemove](#multiRemove)
1414
- [clear](#clear)
1515
- [flushGetRequests](#flushGetRequests)
16+
- [useAsyncStorage](#useAsyncStorage)
1617

1718
<br />
1819

@@ -28,7 +29,7 @@ Fetches a data for a given `key`, invokes (optional) callback once completed.
2829
static getItem(key: string, [callback]: ?(error: ?Error, result: ?string) => void): Promise
2930
```
3031
31-
**Returns**:
32+
**Returns**:
3233
3334
`Promise` with data, if exists, `null` otherwise.
3435
@@ -44,7 +45,7 @@ getMyValue = async () => {
4445
}
4546

4647
console.log('Done'.)
47-
48+
4849
}
4950
```
5051
@@ -78,7 +79,7 @@ setValue = async () => {
7879
} catch(e) {
7980
// save error
8081
}
81-
82+
8283
console.log('Done.')
8384
}
8485
```
@@ -181,7 +182,7 @@ removeValue = async () => {
181182
} catch(e) {
182183
// remove error
183184
}
184-
185+
185186
console.log('Done.')
186187
}
187188
```
@@ -260,7 +261,7 @@ getMultiple = async () => {
260261
// read error
261262
}
262263
console.log(values)
263-
264+
264265
// example console.log output:
265266
// [ ['@MyApp_user', 'myUserValue'], ['@MyApp_key', 'myKeyValue'] ]
266267
}
@@ -299,7 +300,7 @@ multiSet = async () => {
299300
} catch(e) {
300301
//save error
301302
}
302-
303+
303304
console.log("Done.")
304305
}
305306

@@ -372,31 +373,31 @@ mergeMultiple = async () => {
372373
} catch(e) {
373374
// error
374375
}
375-
376+
376377
console.log(currentlyMerged)
377378
// console.log output:
378-
// [
379-
// [
379+
// [
380+
// [
380381
// 'USER_1',
381-
// {
382+
// {
382383
// name:"Tom",
383384
// age:30,
384-
// traits: {
385-
// hair: 'brown'
385+
// traits: {
386+
// hair: 'brown'
386387
// eyes: 'blue'
387388
// }
388389
// }
389390
// ],
390-
// [
391+
// [
391392
// 'USER_2',
392-
// {
393+
// {
393394
// name:'Sarah',
394395
// age:26,
395396
// traits: {
396-
// hair: 'green'
397+
// hair: 'green'
397398
// }
398399
// }
399-
// ]
400+
// ]
400401
// ]
401402
}
402403

@@ -432,10 +433,10 @@ removeFew = async () => {
432433
} catch(e) {
433434
// remove error
434435
}
435-
436+
436437
console.log('Done')
437438
}
438-
439+
439440
```
440441
441442
@@ -467,7 +468,7 @@ clearAll = async () => {
467468
} catch(e) {
468469
// clear error
469470
}
470-
471+
471472
console.log('Done.')
472473
}
473474

@@ -493,4 +494,89 @@ static flushGetRequests(): void
493494
494495
**Returns**:
495496
496-
`undefined`
497+
`undefined`
498+
499+
500+
<!-- ------------------------ HOOKS ------------------------ -->
501+
502+
503+
## `useAsyncStorage`
504+
505+
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.
506+
507+
The `useAsyncStorage` returns an object that exposes all methods that allow you to interact with the stored value.
508+
509+
**Signature**:
510+
511+
```js
512+
static useAsyncStorage(key: string): {
513+
getItem: (
514+
callback?: ?(error: ?Error, result: string | null) => void,
515+
) => Promise<string | null>,
516+
setItem: (
517+
value: string,
518+
callback?: ?(error: ?Error) => void,
519+
) => Promise<null>,
520+
mergeItem: (
521+
value: string,
522+
callback?: ?(error: ?Error) => void,
523+
) => Promise<null>,
524+
removeItem: (callback?: ?(error: ?Error) => void) => Promise<null>,
525+
}
526+
```
527+
528+
**Returns**:
529+
530+
`object`
531+
532+
**Specific Example**:
533+
534+
You can replace your `App.js` with the following to see it in action.
535+
536+
```jsx
537+
import React, { useState, useEffect } from 'react';
538+
import { View, Text, TouchableOpacity } from 'react-native';
539+
import { useAsyncStorage } from '@react-native-community/async-storage';
540+
541+
export default function App() {
542+
const [value, setValue] = useState('value');
543+
const { getItem, setItem } = useAsyncStorage('@storage_key');
544+
545+
const readItemFromStorage = async () => {
546+
const item = await getItem();
547+
setValue(item);
548+
};
549+
550+
const writeItemToStorage = async newValue => {
551+
await setItem(newValue);
552+
setValue(newValue);
553+
};
554+
555+
useEffect(() => {
556+
readItemFromStorage();
557+
}, []);
558+
559+
return (
560+
<View style={{ margin: 40 }}>
561+
<Text>Current value: {value}</Text>
562+
<TouchableOpacity
563+
onPress={() =>
564+
writeItemToStorage(
565+
Math.random()
566+
.toString(36)
567+
.substr(2, 5)
568+
)
569+
}
570+
>
571+
<Text>Update value</Text>
572+
</TouchableOpacity>
573+
</View>
574+
);
575+
}
576+
```
577+
578+
In this example:
579+
580+
1. On mount, we read the value at `@storage_key` and save it to the state under `value`
581+
2. When pressing on "update value", a new string gets generated, saved to async storage, and to the component state
582+
3. Try to reload your app - you'll see that the last value is still being read from async storage

‎lib/AsyncStorage.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -367,4 +367,4 @@ function convertError(error): ?Error {
367367
return out;
368368
}
369369

370-
module.exports = AsyncStorage;
370+
export default AsyncStorage;

‎lib/hooks.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import AsyncStorage from './AsyncStorage';
2+
3+
type AsyncStorageHook = {
4+
getItem: (
5+
callback?: ?(error: ?Error, result: string | null) => void,
6+
) => Promise<string | null>,
7+
setItem: (
8+
value: string,
9+
callback?: ?(error: ?Error) => void,
10+
) => Promise<null>,
11+
mergeItem: (
12+
value: string,
13+
callback?: ?(error: ?Error) => void,
14+
) => Promise<null>,
15+
removeItem: (callback?: ?(error: ?Error) => void) => Promise<null>,
16+
};
17+
18+
export function useAsyncStorage(key: string): AsyncStorageHook {
19+
return {
20+
getItem: (...args) => AsyncStorage.getItem(key, ...args),
21+
setItem: (...args) => AsyncStorage.setItem(key, ...args),
22+
mergeItem: (...args) => AsyncStorage.mergeItem(key, ...args),
23+
removeItem: (...args) => AsyncStorage.removeItem(key, ...args),
24+
};
25+
}

‎lib/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export default from './AsyncStorage';
2+
export { useAsyncStorage } from './hooks';

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "@react-native-community/async-storage",
33
"version": "1.0.2",
44
"description": "Asynchronous, persistent, key-value storage system for React Native.",
5-
"main": "lib/AsyncStorage.js",
5+
"main": "lib/index.js",
66
"author": "Krzysztof Borowy <krizzu.dev@gmail.com>",
77
"contributors": [],
88
"homepage": "https://github.com/react-native-community/react-native-async-storage#readme",

2 commit comments

Comments
 (2)

TheDSCPL commented on Jun 5, 2020

@TheDSCPL
Contributor

This just curries the API calls. There can't be a hook like useState until there is an event being dispatched whenever a change is made, like in web browser's LocalStorage.

TheDSCPL commented on Jun 5, 2020

@TheDSCPL
Contributor

Like this gist tries to do. It doesn't detect changes made to a key if the change is made without using that setValue function (even if it's the same hook on another component).

Please sign in to comment.