Skip to content

Commit 8fc9de7

Browse files
authored
Merge pull request #317 from EvanBacon/LEGACY
[LEGACY] Add web support to AsyncStorage
2 parents 0e3f77a + a99d805 commit 8fc9de7

File tree

6 files changed

+1571
-9
lines changed

6 files changed

+1571
-9
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,5 @@ buck-out/
4747

4848
# Editor config
4949
.vscode
50+
.expo
51+
/web-build

app.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"expo": {
3+
"entryPoint": "./example/index"
4+
}
5+
}

example/index.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@
88
* @flow
99
*/
1010

11-
import {AppRegistry} from 'react-native';
11+
import {AppRegistry, Platform} from 'react-native';
1212
import App from './App';
1313
import {name as appName} from './app.json';
1414

1515
AppRegistry.registerComponent(appName, () => App);
16+
17+
if (Platform.OS === 'web') {
18+
const rootTag = document.getElementById('root');
19+
AppRegistry.runApplication(appName, {rootTag});
20+
}

lib/AsyncStorage.web.js

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/**
2+
* Copyright (c) Nicolas Gallagher.
3+
* Copyright (c) Facebook, Inc. and its affiliates.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*
8+
* @flow
9+
*/
10+
11+
import merge from 'deep-assign';
12+
13+
const mergeLocalStorageItem = (key, value) => {
14+
const oldValue = window.localStorage.getItem(key);
15+
const oldObject = JSON.parse(oldValue);
16+
const newObject = JSON.parse(value);
17+
const nextValue = JSON.stringify(merge({}, oldObject, newObject));
18+
window.localStorage.setItem(key, nextValue);
19+
};
20+
21+
const createPromise = (getValue, callback): Promise<*> => {
22+
return new Promise((resolve, reject) => {
23+
try {
24+
const value = getValue();
25+
if (callback) {
26+
callback(null, value);
27+
}
28+
resolve(value);
29+
} catch (err) {
30+
if (callback) {
31+
callback(err);
32+
}
33+
reject(err);
34+
}
35+
});
36+
};
37+
38+
const createPromiseAll = (promises, callback, processResult): Promise<*> => {
39+
return Promise.all(promises).then(
40+
result => {
41+
const value = processResult ? processResult(result) : null;
42+
callback && callback(null, value);
43+
return Promise.resolve(value);
44+
},
45+
errors => {
46+
callback && callback(errors);
47+
return Promise.reject(errors);
48+
}
49+
);
50+
};
51+
52+
export default class AsyncStorage {
53+
54+
/**
55+
* Fetches `key` value.
56+
*/
57+
static getItem(key: string, callback?: Function): Promise<*> {
58+
return createPromise(() => {
59+
return window.localStorage.getItem(key);
60+
}, callback);
61+
}
62+
63+
/**
64+
* Sets `value` for `key`.
65+
*/
66+
static setItem(key: string, value: string, callback?: Function): Promise<*> {
67+
return createPromise(() => {
68+
window.localStorage.setItem(key, value);
69+
}, callback);
70+
}
71+
72+
/**
73+
* Removes a `key`
74+
*/
75+
static removeItem(key: string, callback?: Function): Promise<*> {
76+
return createPromise(() => {
77+
return window.localStorage.removeItem(key);
78+
}, callback);
79+
}
80+
81+
/**
82+
* Merges existing value with input value, assuming they are stringified JSON.
83+
*/
84+
static mergeItem(key: string, value: string, callback?: Function): Promise<*> {
85+
return createPromise(() => {
86+
mergeLocalStorageItem(key, value);
87+
}, callback);
88+
}
89+
90+
/**
91+
* Erases *all* AsyncStorage for the domain.
92+
*/
93+
static clear(callback?: Function): Promise<*> {
94+
return createPromise(() => {
95+
window.localStorage.clear();
96+
}, callback);
97+
}
98+
99+
/**
100+
* Gets *all* keys known to the app, for all callers, libraries, etc.
101+
*/
102+
static getAllKeys(callback?: Function): Promise<*> {
103+
return createPromise(() => {
104+
const numberOfKeys = window.localStorage.length;
105+
const keys = [];
106+
for (let i = 0; i < numberOfKeys; i += 1) {
107+
const key = window.localStorage.key(i);
108+
keys.push(key);
109+
}
110+
return keys;
111+
}, callback);
112+
}
113+
114+
/**
115+
* (stub) Flushes any pending requests using a single batch call to get the data.
116+
*/
117+
static flushGetRequests() {}
118+
119+
/**
120+
* multiGet resolves to an array of key-value pair arrays that matches the
121+
* input format of multiSet.
122+
*
123+
* multiGet(['k1', 'k2']) -> [['k1', 'val1'], ['k2', 'val2']]
124+
*/
125+
static multiGet(keys: Array<string>, callback?: Function): Promise<*> {
126+
const promises = keys.map(key => AsyncStorage.getItem(key));
127+
const processResult = result => result.map((value, i) => [keys[i], value]);
128+
return createPromiseAll(promises, callback, processResult);
129+
}
130+
131+
/**
132+
* Takes an array of key-value array pairs.
133+
* multiSet([['k1', 'val1'], ['k2', 'val2']])
134+
*/
135+
static multiSet(keyValuePairs: Array<Array<string>>, callback?: Function): Promise<*> {
136+
const promises = keyValuePairs.map(item => AsyncStorage.setItem(item[0], item[1]));
137+
return createPromiseAll(promises, callback);
138+
}
139+
140+
/**
141+
* Delete all the keys in the `keys` array.
142+
*/
143+
static multiRemove(keys: Array<string>, callback?: Function): Promise<*> {
144+
const promises = keys.map(key => AsyncStorage.removeItem(key));
145+
return createPromiseAll(promises, callback);
146+
}
147+
148+
/**
149+
* Takes an array of key-value array pairs and merges them with existing
150+
* values, assuming they are stringified JSON.
151+
*
152+
* multiMerge([['k1', 'val1'], ['k2', 'val2']])
153+
*/
154+
static multiMerge(keyValuePairs: Array<Array<string>>, callback?: Function): Promise<*> {
155+
const promises = keyValuePairs.map(item => AsyncStorage.mergeItem(item[0], item[1]));
156+
return createPromiseAll(promises, callback);
157+
}
158+
}

package.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
"types": "./types/index.d.ts",
66
"main": "./lib/index.js",
77
"author": "Krzysztof Borowy <[email protected]>",
8-
"contributors": [],
8+
"contributors": [
9+
"Evan Bacon <[email protected]> (https://github.com/evanbacon)"
10+
],
911
"homepage": "https://github.com/react-native-community/react-native-async-storage#readme",
1012
"license": "MIT",
1113
"keywords": [
@@ -23,6 +25,7 @@
2325
"start": "node node_modules/react-native/local-cli/cli.js start",
2426
"start:android": "react-native run-android --root example/",
2527
"start:ios": "react-native run-ios --project-path example/ios --scheme AsyncStorageExample",
28+
"start:web": "expo start:web",
2629
"start:macos": "node node_modules/react-native-macos/local-cli/cli.js start --use-react-native-macos",
2730
"build:e2e:ios": "detox build -c ios",
2831
"build:e2e:android": "detox build -c android",
@@ -38,19 +41,25 @@
3841
"react": "^16.8",
3942
"react-native": ">=0.59"
4043
},
44+
"dependencies": {
45+
"deep-assign": "^3.0.0"
46+
},
4147
"devDependencies": {
4248
"@babel/core": "7.4.5",
4349
"@babel/runtime": "7.4.5",
4450
"@react-native-community/eslint-config": "0.0.2",
4551
"babel-jest": "24.8.0",
4652
"babel-plugin-module-resolver": "3.1.3",
4753
"detox": "12.6.1",
54+
"expo": "36.0.2",
4855
"eslint": "5.1.0",
4956
"flow-bin": "0.92.0",
5057
"jest": "24.8.0",
5158
"metro-react-native-babel-preset": "0.54.1",
5259
"react": "16.6.3",
60+
"react-dom": "16.6.3",
5361
"react-native": "0.59.10",
62+
"react-native-web": "~0.12.0",
5463
"react-native-macos": "0.60.0-microsoft.50",
5564
"react-test-renderer": "16.8.3"
5665
},

0 commit comments

Comments
 (0)