Skip to content

Commit

Permalink
Merge pull request #317 from EvanBacon/LEGACY
Browse files Browse the repository at this point in the history
[LEGACY] Add web support to AsyncStorage
  • Loading branch information
EvanBacon authored Apr 1, 2020
2 parents 0e3f77a + a99d805 commit 8fc9de7
Show file tree
Hide file tree
Showing 6 changed files with 1,571 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,5 @@ buck-out/

# Editor config
.vscode
.expo
/web-build
5 changes: 5 additions & 0 deletions app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"expo": {
"entryPoint": "./example/index"
}
}
7 changes: 6 additions & 1 deletion example/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@
* @flow
*/

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

AppRegistry.registerComponent(appName, () => App);

if (Platform.OS === 'web') {
const rootTag = document.getElementById('root');
AppRegistry.runApplication(appName, {rootTag});
}
158 changes: 158 additions & 0 deletions lib/AsyncStorage.web.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/**
* Copyright (c) Nicolas Gallagher.
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import merge from 'deep-assign';

const mergeLocalStorageItem = (key, value) => {
const oldValue = window.localStorage.getItem(key);
const oldObject = JSON.parse(oldValue);
const newObject = JSON.parse(value);
const nextValue = JSON.stringify(merge({}, oldObject, newObject));
window.localStorage.setItem(key, nextValue);
};

const createPromise = (getValue, callback): Promise<*> => {
return new Promise((resolve, reject) => {
try {
const value = getValue();
if (callback) {
callback(null, value);
}
resolve(value);
} catch (err) {
if (callback) {
callback(err);
}
reject(err);
}
});
};

const createPromiseAll = (promises, callback, processResult): Promise<*> => {
return Promise.all(promises).then(
result => {
const value = processResult ? processResult(result) : null;
callback && callback(null, value);
return Promise.resolve(value);
},
errors => {
callback && callback(errors);
return Promise.reject(errors);
}
);
};

export default class AsyncStorage {

/**
* Fetches `key` value.
*/
static getItem(key: string, callback?: Function): Promise<*> {
return createPromise(() => {
return window.localStorage.getItem(key);
}, callback);
}

/**
* Sets `value` for `key`.
*/
static setItem(key: string, value: string, callback?: Function): Promise<*> {
return createPromise(() => {
window.localStorage.setItem(key, value);
}, callback);
}

/**
* Removes a `key`
*/
static removeItem(key: string, callback?: Function): Promise<*> {
return createPromise(() => {
return window.localStorage.removeItem(key);
}, callback);
}

/**
* Merges existing value with input value, assuming they are stringified JSON.
*/
static mergeItem(key: string, value: string, callback?: Function): Promise<*> {
return createPromise(() => {
mergeLocalStorageItem(key, value);
}, callback);
}

/**
* Erases *all* AsyncStorage for the domain.
*/
static clear(callback?: Function): Promise<*> {
return createPromise(() => {
window.localStorage.clear();
}, callback);
}

/**
* Gets *all* keys known to the app, for all callers, libraries, etc.
*/
static getAllKeys(callback?: Function): Promise<*> {
return createPromise(() => {
const numberOfKeys = window.localStorage.length;
const keys = [];
for (let i = 0; i < numberOfKeys; i += 1) {
const key = window.localStorage.key(i);
keys.push(key);
}
return keys;
}, callback);
}

/**
* (stub) Flushes any pending requests using a single batch call to get the data.
*/
static flushGetRequests() {}

/**
* multiGet resolves to an array of key-value pair arrays that matches the
* input format of multiSet.
*
* multiGet(['k1', 'k2']) -> [['k1', 'val1'], ['k2', 'val2']]
*/
static multiGet(keys: Array<string>, callback?: Function): Promise<*> {
const promises = keys.map(key => AsyncStorage.getItem(key));
const processResult = result => result.map((value, i) => [keys[i], value]);
return createPromiseAll(promises, callback, processResult);
}

/**
* Takes an array of key-value array pairs.
* multiSet([['k1', 'val1'], ['k2', 'val2']])
*/
static multiSet(keyValuePairs: Array<Array<string>>, callback?: Function): Promise<*> {
const promises = keyValuePairs.map(item => AsyncStorage.setItem(item[0], item[1]));
return createPromiseAll(promises, callback);
}

/**
* Delete all the keys in the `keys` array.
*/
static multiRemove(keys: Array<string>, callback?: Function): Promise<*> {
const promises = keys.map(key => AsyncStorage.removeItem(key));
return createPromiseAll(promises, callback);
}

/**
* Takes an array of key-value array pairs and merges them with existing
* values, assuming they are stringified JSON.
*
* multiMerge([['k1', 'val1'], ['k2', 'val2']])
*/
static multiMerge(keyValuePairs: Array<Array<string>>, callback?: Function): Promise<*> {
const promises = keyValuePairs.map(item => AsyncStorage.mergeItem(item[0], item[1]));
return createPromiseAll(promises, callback);
}
}
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"types": "./types/index.d.ts",
"main": "./lib/index.js",
"author": "Krzysztof Borowy <[email protected]>",
"contributors": [],
"contributors": [
"Evan Bacon <[email protected]> (https://github.com/evanbacon)"
],
"homepage": "https://github.com/react-native-community/react-native-async-storage#readme",
"license": "MIT",
"keywords": [
Expand All @@ -23,6 +25,7 @@
"start": "node node_modules/react-native/local-cli/cli.js start",
"start:android": "react-native run-android --root example/",
"start:ios": "react-native run-ios --project-path example/ios --scheme AsyncStorageExample",
"start:web": "expo start:web",
"start:macos": "node node_modules/react-native-macos/local-cli/cli.js start --use-react-native-macos",
"build:e2e:ios": "detox build -c ios",
"build:e2e:android": "detox build -c android",
Expand All @@ -38,19 +41,25 @@
"react": "^16.8",
"react-native": ">=0.59"
},
"dependencies": {
"deep-assign": "^3.0.0"
},
"devDependencies": {
"@babel/core": "7.4.5",
"@babel/runtime": "7.4.5",
"@react-native-community/eslint-config": "0.0.2",
"babel-jest": "24.8.0",
"babel-plugin-module-resolver": "3.1.3",
"detox": "12.6.1",
"expo": "36.0.2",
"eslint": "5.1.0",
"flow-bin": "0.92.0",
"jest": "24.8.0",
"metro-react-native-babel-preset": "0.54.1",
"react": "16.6.3",
"react-dom": "16.6.3",
"react-native": "0.59.10",
"react-native-web": "~0.12.0",
"react-native-macos": "0.60.0-microsoft.50",
"react-test-renderer": "16.8.3"
},
Expand Down
Loading

0 comments on commit 8fc9de7

Please sign in to comment.