mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
refactor(react-native-github): remove AsyncStorage from JS
Summary: ## Changelog [JS][Removed] - Removed AsyncStorage module from react-native Reviewed By: NickGerleman Differential Revision: D40302352 fbshipit-source-id: 9377ea12036e498dde0b4b0f56de5c4fb9bd2461
This commit is contained in:
committed by
Facebook GitHub Bot
parent
4de2aaba50
commit
20eeb1bfe3
@@ -1,261 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const React = require('react');
|
||||
const ReactNative = require('react-native');
|
||||
const {AsyncStorage, Text, View, StyleSheet} = ReactNative;
|
||||
const {TestModule} = ReactNative.NativeModules;
|
||||
|
||||
const deepDiffer = require('react-native/Libraries/Utilities/differ/deepDiffer');
|
||||
const nullthrows = require('nullthrows');
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
const KEY_1 = 'key_1';
|
||||
const VAL_1 = 'val_1';
|
||||
const KEY_2 = 'key_2';
|
||||
const VAL_2 = 'val_2';
|
||||
const KEY_MERGE = 'key_merge';
|
||||
const VAL_MERGE_1 = {foo: 1, bar: {hoo: 1, boo: 1}, moo: {a: 3}};
|
||||
const VAL_MERGE_2 = {bar: {hoo: 2}, baz: 2, moo: {a: 3}};
|
||||
const VAL_MERGE_EXPECT = {foo: 1, bar: {hoo: 2, boo: 1}, baz: 2, moo: {a: 3}};
|
||||
|
||||
// setup in componentDidMount
|
||||
let done = (result: ?boolean) => {};
|
||||
let updateMessage = (message: string) => {};
|
||||
|
||||
function runTestCase(description: string, fn: () => void) {
|
||||
updateMessage(description);
|
||||
fn();
|
||||
}
|
||||
|
||||
function expectTrue(condition: boolean, message: string) {
|
||||
if (!condition) {
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
// Type-safe wrapper around JSON.stringify
|
||||
function stringify(
|
||||
value:
|
||||
| void
|
||||
| null
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| {...}
|
||||
| $ReadOnlyArray<mixed>,
|
||||
): string {
|
||||
if (typeof value === 'undefined') {
|
||||
return 'undefined';
|
||||
}
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
||||
function expectEqual(
|
||||
lhs: ?(any | string | Array<Array<string>>),
|
||||
rhs:
|
||||
| null
|
||||
| string
|
||||
| {
|
||||
bar: {boo: number, hoo: number},
|
||||
baz: number,
|
||||
foo: number,
|
||||
moo: {a: number},
|
||||
}
|
||||
| Array<Array<string>>,
|
||||
testname: string,
|
||||
) {
|
||||
expectTrue(
|
||||
!deepDiffer(lhs, rhs),
|
||||
'Error in test ' +
|
||||
testname +
|
||||
': expected\n' +
|
||||
stringify(rhs) +
|
||||
'\ngot\n' +
|
||||
stringify(lhs),
|
||||
);
|
||||
}
|
||||
|
||||
function expectAsyncNoError(
|
||||
place: string,
|
||||
err: ?(Error | string | Array<Error>),
|
||||
) {
|
||||
if (err instanceof Error) {
|
||||
err = err.message;
|
||||
}
|
||||
expectTrue(
|
||||
err === null,
|
||||
'Unexpected error in ' + place + ': ' + stringify(err),
|
||||
);
|
||||
}
|
||||
|
||||
function testSetAndGet() {
|
||||
AsyncStorage.setItem(KEY_1, VAL_1, err1 => {
|
||||
expectAsyncNoError('testSetAndGet/setItem', err1);
|
||||
AsyncStorage.getItem(KEY_1, (err2, result) => {
|
||||
expectAsyncNoError('testSetAndGet/getItem', err2);
|
||||
expectEqual(result, VAL_1, 'testSetAndGet setItem');
|
||||
updateMessage('get(key_1) correctly returned ' + String(result));
|
||||
runTestCase('should get null for missing key', testMissingGet);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testMissingGet() {
|
||||
AsyncStorage.getItem(KEY_2, (err, result) => {
|
||||
expectAsyncNoError('testMissingGet/setItem', err);
|
||||
expectEqual(result, null, 'testMissingGet');
|
||||
updateMessage('missing get(key_2) correctly returned ' + String(result));
|
||||
runTestCase('check set twice results in a single key', testSetTwice);
|
||||
});
|
||||
}
|
||||
|
||||
function testSetTwice() {
|
||||
AsyncStorage.setItem(KEY_1, VAL_1, () => {
|
||||
AsyncStorage.setItem(KEY_1, VAL_1, () => {
|
||||
AsyncStorage.getItem(KEY_1, (err, result) => {
|
||||
expectAsyncNoError('testSetTwice/setItem', err);
|
||||
expectEqual(result, VAL_1, 'testSetTwice');
|
||||
updateMessage('setTwice worked as expected');
|
||||
runTestCase('test removeItem', testRemoveItem);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testRemoveItem() {
|
||||
AsyncStorage.setItem(KEY_1, VAL_1, () => {
|
||||
AsyncStorage.setItem(KEY_2, VAL_2, () => {
|
||||
AsyncStorage.getAllKeys((err, result) => {
|
||||
expectAsyncNoError('testRemoveItem/getAllKeys', err);
|
||||
expectTrue(
|
||||
nullthrows(result).indexOf(KEY_1) >= 0 &&
|
||||
nullthrows(result).indexOf(KEY_2) >= 0,
|
||||
'Missing KEY_1 or KEY_2 in ' + '(' + nullthrows(result).join() + ')',
|
||||
);
|
||||
updateMessage('testRemoveItem - add two items');
|
||||
AsyncStorage.removeItem(KEY_1, err2 => {
|
||||
expectAsyncNoError('testRemoveItem/removeItem', err2);
|
||||
updateMessage('delete successful ');
|
||||
AsyncStorage.getItem(KEY_1, (err3, result2) => {
|
||||
expectAsyncNoError('testRemoveItem/getItem', err3);
|
||||
expectEqual(
|
||||
result2,
|
||||
null,
|
||||
'testRemoveItem: key_1 present after delete',
|
||||
);
|
||||
updateMessage('key properly removed ');
|
||||
AsyncStorage.getAllKeys((err4, result3) => {
|
||||
expectAsyncNoError('testRemoveItem/getAllKeys', err4);
|
||||
expectTrue(
|
||||
nullthrows(result3).indexOf(KEY_1) === -1,
|
||||
'Unexpected: KEY_1 present in ' + nullthrows(result3).join(),
|
||||
);
|
||||
updateMessage('proper length returned.');
|
||||
runTestCase('should merge values', testMerge);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testMerge() {
|
||||
AsyncStorage.setItem(KEY_MERGE, stringify(VAL_MERGE_1), err1 => {
|
||||
expectAsyncNoError('testMerge/setItem', err1);
|
||||
AsyncStorage.mergeItem(KEY_MERGE, stringify(VAL_MERGE_2), err2 => {
|
||||
expectAsyncNoError('testMerge/mergeItem', err2);
|
||||
AsyncStorage.getItem(KEY_MERGE, (err3, result) => {
|
||||
expectAsyncNoError('testMerge/setItem', err3);
|
||||
expectEqual(
|
||||
JSON.parse(nullthrows(result)),
|
||||
VAL_MERGE_EXPECT,
|
||||
'testMerge',
|
||||
);
|
||||
updateMessage('objects deeply merged\nDone!');
|
||||
runTestCase('multi set and get', testOptimizedMultiGet);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testOptimizedMultiGet() {
|
||||
let batch = [
|
||||
[KEY_1, VAL_1],
|
||||
[KEY_2, VAL_2],
|
||||
];
|
||||
let keys = batch.map(([key, value]) => key);
|
||||
AsyncStorage.multiSet(batch, err1 => {
|
||||
// yes, twice on purpose
|
||||
[1, 2].forEach(i => {
|
||||
expectAsyncNoError(`${i} testOptimizedMultiGet/multiSet`, err1);
|
||||
AsyncStorage.multiGet(keys, (err2, result) => {
|
||||
expectAsyncNoError(`${i} testOptimizedMultiGet/multiGet`, err2);
|
||||
expectEqual(result, batch, `${i} testOptimizedMultiGet multiGet`);
|
||||
updateMessage(
|
||||
'multiGet([key_1, key_2]) correctly returned ' + stringify(result),
|
||||
);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class AsyncStorageTest extends React.Component<{...}, $FlowFixMeState> {
|
||||
state: any | {|done: boolean, messages: string|} = {
|
||||
messages: 'Initializing...',
|
||||
done: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
done = () =>
|
||||
this.setState({done: true}, () => {
|
||||
TestModule.markTestCompleted();
|
||||
});
|
||||
updateMessage = (msg: string) => {
|
||||
this.setState({messages: this.state.messages.concat('\n' + msg)});
|
||||
DEBUG && console.log(msg);
|
||||
};
|
||||
AsyncStorage.clear(testSetAndGet);
|
||||
}
|
||||
|
||||
render(): React.Node {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>
|
||||
{
|
||||
/* $FlowFixMe[incompatible-type] (>=0.54.0 site=react_native_fb,react_
|
||||
* native_oss) This comment suppresses an error found when Flow v0.54
|
||||
* was deployed. To see the error delete this comment and run Flow.
|
||||
*/
|
||||
this.constructor.displayName + ': '
|
||||
}
|
||||
{this.state.done ? 'Done' : 'Testing...'}
|
||||
{'\n\n' + this.state.messages}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: 'white',
|
||||
padding: 40,
|
||||
},
|
||||
});
|
||||
|
||||
AsyncStorageTest.displayName = 'AsyncStorageTest';
|
||||
|
||||
module.exports = AsyncStorageTest;
|
||||
@@ -20,7 +20,6 @@ const {AppRegistry, ScrollView, StyleSheet, Text, TouchableOpacity, View} =
|
||||
const TESTS = [
|
||||
require('./IntegrationTestHarnessTest'),
|
||||
require('./TimersTest'),
|
||||
require('./AsyncStorageTest'),
|
||||
require('./LayoutEventsTest'),
|
||||
require('./AppEventsTest'),
|
||||
require('./SimpleSnapshotTest'),
|
||||
|
||||
Vendored
-120
@@ -1,120 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
/**
|
||||
* AsyncStorage is a simple, unencrypted, asynchronous, persistent, key-value storage
|
||||
* system that is global to the app. It should be used instead of LocalStorage.
|
||||
*
|
||||
* It is recommended that you use an abstraction on top of `AsyncStorage`
|
||||
* instead of `AsyncStorage` directly for anything more than light usage since
|
||||
* it operates globally.
|
||||
*
|
||||
* On iOS, `AsyncStorage` is backed by native code that stores small values in a
|
||||
* serialized dictionary and larger values in separate files. On Android,
|
||||
* `AsyncStorage` will use either [RocksDB](http://rocksdb.org/) or SQLite
|
||||
* based on what is available.
|
||||
*
|
||||
* @see https://reactnative.dev/docs/asyncstorage#content
|
||||
*/
|
||||
export interface AsyncStorageStatic {
|
||||
/**
|
||||
* Fetches key and passes the result to callback, along with an Error if there is any.
|
||||
*/
|
||||
getItem(
|
||||
key: string,
|
||||
callback?: (error?: Error, result?: string) => void,
|
||||
): Promise<string | null>;
|
||||
|
||||
/**
|
||||
* Sets value for key and calls callback on completion, along with an Error if there is any
|
||||
*/
|
||||
setItem(
|
||||
key: string,
|
||||
value: string,
|
||||
callback?: (error?: Error) => void,
|
||||
): Promise<void>;
|
||||
|
||||
removeItem(key: string, callback?: (error?: Error) => void): Promise<void>;
|
||||
|
||||
/**
|
||||
* Merges existing value with input value, assuming they are stringified json. Returns a Promise object.
|
||||
* Not supported by all native implementation
|
||||
*/
|
||||
mergeItem(
|
||||
key: string,
|
||||
value: string,
|
||||
callback?: (error?: Error) => void,
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Erases all AsyncStorage for all clients, libraries, etc. You probably don't want to call this.
|
||||
* Use removeItem or multiRemove to clear only your own keys instead.
|
||||
*/
|
||||
clear(callback?: (error?: Error) => void): Promise<void>;
|
||||
|
||||
/**
|
||||
* Gets all keys known to the app, for all callers, libraries, etc
|
||||
*/
|
||||
getAllKeys(
|
||||
callback?: (error?: Error, keys?: string[]) => void,
|
||||
): Promise<string[]>;
|
||||
|
||||
/**
|
||||
* multiGet invokes callback with an array of key-value pair arrays that matches the input format of multiSet
|
||||
*/
|
||||
multiGet(
|
||||
keys: string[],
|
||||
callback?: (errors?: Error[], result?: [string, string][]) => void,
|
||||
): Promise<[string, string][]>;
|
||||
|
||||
/**
|
||||
* multiSet and multiMerge take arrays of key-value array pairs that match the output of multiGet,
|
||||
*
|
||||
* multiSet([['k1', 'val1'], ['k2', 'val2']], cb);
|
||||
*/
|
||||
multiSet(
|
||||
keyValuePairs: string[][],
|
||||
callback?: (errors?: Error[]) => void,
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Delete all the keys in the keys array.
|
||||
*/
|
||||
multiRemove(
|
||||
keys: string[],
|
||||
callback?: (errors?: Error[]) => void,
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Merges existing values with input values, assuming they are stringified json.
|
||||
* Returns a Promise object.
|
||||
*
|
||||
* Not supported by all native implementations.
|
||||
*/
|
||||
multiMerge(
|
||||
keyValuePairs: string[][],
|
||||
callback?: (errors?: Error[]) => void,
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* AsyncStorage has been extracted from react-native core and will be removed in a future release.
|
||||
* It can now be installed and imported from `@react-native-community/async-storage` instead of 'react-native'.
|
||||
* @see https://github.com/react-native-community/async-storage
|
||||
* @deprecated
|
||||
*/
|
||||
export const AsyncStorage: AsyncStorageStatic;
|
||||
|
||||
/**
|
||||
* AsyncStorage has been extracted from react-native core and will be removed in a future release.
|
||||
* It can now be installed and imported from `@react-native-community/async-storage` instead of 'react-native'.
|
||||
* @see https://github.com/react-native-community/async-storage
|
||||
* @deprecated
|
||||
*/
|
||||
export type AsyncStorage = AsyncStorageStatic;
|
||||
@@ -1,385 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow strict
|
||||
* @jsdoc
|
||||
*/
|
||||
|
||||
import NativeAsyncLocalStorage from './NativeAsyncLocalStorage';
|
||||
import NativeAsyncSQLiteDBStorage from './NativeAsyncSQLiteDBStorage';
|
||||
import invariant from 'invariant';
|
||||
|
||||
// Use SQLite if available, otherwise file storage.
|
||||
const RCTAsyncStorage = NativeAsyncSQLiteDBStorage || NativeAsyncLocalStorage;
|
||||
|
||||
type GetRequest = {
|
||||
keys: Array<string>,
|
||||
callback: ?(errors: ?Array<Error>, result: ?Array<Array<string>>) => void,
|
||||
keyIndex: number,
|
||||
resolve: (
|
||||
result?:
|
||||
| void
|
||||
| null
|
||||
| Promise<?Array<Array<string>>>
|
||||
| Array<Array<string>>,
|
||||
) => void,
|
||||
reject: (error?: mixed) => void,
|
||||
};
|
||||
|
||||
/**
|
||||
* `AsyncStorage` is a simple, unencrypted, asynchronous, persistent, key-value
|
||||
* storage system that is global to the app. It should be used instead of
|
||||
* LocalStorage.
|
||||
*
|
||||
* See https://reactnative.dev/docs/asyncstorage
|
||||
*/
|
||||
const AsyncStorage = {
|
||||
_getRequests: ([]: Array<GetRequest>),
|
||||
_getKeys: ([]: Array<string>),
|
||||
_immediate: (null: ?number),
|
||||
|
||||
/**
|
||||
* Fetches an item for a `key` and invokes a callback upon completion.
|
||||
*
|
||||
* See https://reactnative.dev/docs/asyncstorage#getitem
|
||||
*/
|
||||
getItem: function (
|
||||
key: string,
|
||||
callback?: ?(error: ?Error, result: ?string) => void,
|
||||
): Promise<?string> {
|
||||
invariant(RCTAsyncStorage, 'RCTAsyncStorage not available');
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiGet([key], function (errors, result) {
|
||||
// Unpack result to get value from [[key,value]]
|
||||
const value = result && result[0] && result[0][1] ? result[0][1] : null;
|
||||
const errs = convertErrors(errors);
|
||||
callback && callback(errs && errs[0], value);
|
||||
if (errs) {
|
||||
reject(errs[0]);
|
||||
} else {
|
||||
resolve(value);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the value for a `key` and invokes a callback upon completion.
|
||||
*
|
||||
* See https://reactnative.dev/docs/asyncstorage#setitem
|
||||
*/
|
||||
setItem: function (
|
||||
key: string,
|
||||
value: string,
|
||||
callback?: ?(error: ?Error) => void,
|
||||
): Promise<void> {
|
||||
invariant(RCTAsyncStorage, 'RCTAsyncStorage not available');
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiSet([[key, value]], function (errors) {
|
||||
const errs = convertErrors(errors);
|
||||
callback && callback(errs && errs[0]);
|
||||
if (errs) {
|
||||
reject(errs[0]);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes an item for a `key` and invokes a callback upon completion.
|
||||
*
|
||||
* See https://reactnative.dev/docs/asyncstorage#removeitem
|
||||
*/
|
||||
removeItem: function (
|
||||
key: string,
|
||||
callback?: ?(error: ?Error) => void,
|
||||
): Promise<void> {
|
||||
invariant(RCTAsyncStorage, 'RCTAsyncStorage not available');
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiRemove([key], function (errors) {
|
||||
const errs = convertErrors(errors);
|
||||
callback && callback(errs && errs[0]);
|
||||
if (errs) {
|
||||
reject(errs[0]);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Merges an existing `key` value with an input value, assuming both values
|
||||
* are stringified JSON.
|
||||
*
|
||||
* **NOTE:** This is not supported by all native implementations.
|
||||
*
|
||||
* See https://reactnative.dev/docs/asyncstorage#mergeitem
|
||||
*/
|
||||
mergeItem: function (
|
||||
key: string,
|
||||
value: string,
|
||||
callback?: ?(error: ?Error) => void,
|
||||
): Promise<void> {
|
||||
invariant(RCTAsyncStorage, 'RCTAsyncStorage not available');
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiMerge([[key, value]], function (errors) {
|
||||
const errs = convertErrors(errors);
|
||||
callback && callback(errs && errs[0]);
|
||||
if (errs) {
|
||||
reject(errs[0]);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Erases *all* `AsyncStorage` for all clients, libraries, etc. You probably
|
||||
* don't want to call this; use `removeItem` or `multiRemove` to clear only
|
||||
* your app's keys.
|
||||
*
|
||||
* See https://reactnative.dev/docs/asyncstorage#clear
|
||||
*/
|
||||
clear: function (callback?: ?(error: ?Error) => void): Promise<void> {
|
||||
invariant(RCTAsyncStorage, 'RCTAsyncStorage not available');
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.clear(function (error) {
|
||||
callback && callback(convertError(error));
|
||||
if (error && convertError(error)) {
|
||||
reject(convertError(error));
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets *all* keys known to your app; for all callers, libraries, etc.
|
||||
*
|
||||
* See https://reactnative.dev/docs/asyncstorage#getallkeys
|
||||
*/
|
||||
getAllKeys: function (
|
||||
callback?: ?(error: ?Error, keys: ?Array<string>) => void,
|
||||
): Promise<?Array<string>> {
|
||||
invariant(RCTAsyncStorage, 'RCTAsyncStorage not available');
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.getAllKeys(function (error, keys) {
|
||||
callback && callback(convertError(error), keys);
|
||||
if (error) {
|
||||
reject(convertError(error));
|
||||
} else {
|
||||
resolve(keys);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* The following batched functions are useful for executing a lot of
|
||||
* operations at once, allowing for native optimizations and provide the
|
||||
* convenience of a single callback after all operations are complete.
|
||||
*
|
||||
* These functions return arrays of errors, potentially one for every key.
|
||||
* For key-specific errors, the Error object will have a key property to
|
||||
* indicate which key caused the error.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Flushes any pending requests using a single batch call to get the data.
|
||||
*
|
||||
* See https://reactnative.dev/docs/asyncstorage#flushgetrequests
|
||||
* */
|
||||
/* $FlowFixMe[missing-this-annot] The 'this' type annotation(s) required by
|
||||
* Flow's LTI update could not be added via codemod */
|
||||
flushGetRequests: function (): void {
|
||||
const getRequests = this._getRequests;
|
||||
const getKeys = this._getKeys;
|
||||
|
||||
this._getRequests = [];
|
||||
this._getKeys = [];
|
||||
|
||||
invariant(RCTAsyncStorage, 'RCTAsyncStorage not available');
|
||||
RCTAsyncStorage.multiGet(getKeys, function (errors, result) {
|
||||
// Even though the runtime complexity of this is theoretically worse vs if we used a map,
|
||||
// it's much, much faster in practice for the data sets we deal with (we avoid
|
||||
// allocating result pair arrays). This was heavily benchmarked.
|
||||
//
|
||||
// Is there a way to avoid using the map but fix the bug in this breaking test?
|
||||
// https://github.com/facebook/react-native/commit/8dd8ad76579d7feef34c014d387bf02065692264
|
||||
const map: {[string]: string} = {};
|
||||
result &&
|
||||
result.forEach(([key, value]) => {
|
||||
map[key] = value;
|
||||
return value;
|
||||
});
|
||||
const reqLength = getRequests.length;
|
||||
for (let i = 0; i < reqLength; i++) {
|
||||
const request = getRequests[i];
|
||||
const requestKeys = request.keys;
|
||||
const requestResult = requestKeys.map(key => [key, map[key]]);
|
||||
request.callback && request.callback(null, requestResult);
|
||||
request.resolve && request.resolve(requestResult);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* This allows you to batch the fetching of items given an array of `key`
|
||||
* inputs. Your callback will be invoked with an array of corresponding
|
||||
* key-value pairs found.
|
||||
*
|
||||
* See https://reactnative.dev/docs/asyncstorage#multiget
|
||||
*/
|
||||
/* $FlowFixMe[missing-this-annot] The 'this' type annotation(s) required by
|
||||
* Flow's LTI update could not be added via codemod */
|
||||
multiGet: function (
|
||||
keys: Array<string>,
|
||||
callback?: ?(errors: ?Array<Error>, result: ?Array<Array<string>>) => void,
|
||||
): Promise<?Array<Array<string>>> {
|
||||
if (!this._immediate) {
|
||||
this._immediate = setImmediate(() => {
|
||||
this._immediate = null;
|
||||
this.flushGetRequests();
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise<?Array<Array<string>>>((resolve, reject) => {
|
||||
this._getRequests.push({
|
||||
keys,
|
||||
callback,
|
||||
// do we need this?
|
||||
keyIndex: this._getKeys.length,
|
||||
resolve,
|
||||
reject,
|
||||
});
|
||||
// avoid fetching duplicates
|
||||
keys.forEach(key => {
|
||||
if (this._getKeys.indexOf(key) === -1) {
|
||||
this._getKeys.push(key);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Use this as a batch operation for storing multiple key-value pairs. When
|
||||
* the operation completes you'll get a single callback with any errors.
|
||||
*
|
||||
* See https://reactnative.dev/docs/asyncstorage#multiset
|
||||
*/
|
||||
multiSet: function (
|
||||
keyValuePairs: Array<Array<string>>,
|
||||
callback?: ?(errors: ?Array<Error>) => void,
|
||||
): Promise<void> {
|
||||
invariant(RCTAsyncStorage, 'RCTAsyncStorage not available');
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiSet(keyValuePairs, function (errors) {
|
||||
const error = convertErrors(errors);
|
||||
callback && callback(error);
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Call this to batch the deletion of all keys in the `keys` array.
|
||||
*
|
||||
* See https://reactnative.dev/docs/asyncstorage#multiremove
|
||||
*/
|
||||
multiRemove: function (
|
||||
keys: Array<string>,
|
||||
callback?: ?(errors: ?Array<Error>) => void,
|
||||
): Promise<void> {
|
||||
invariant(RCTAsyncStorage, 'RCTAsyncStorage not available');
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiRemove(keys, function (errors) {
|
||||
const error = convertErrors(errors);
|
||||
callback && callback(error);
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Batch operation to merge in existing and new values for a given set of
|
||||
* keys. This assumes that the values are stringified JSON.
|
||||
*
|
||||
* **NOTE**: This is not supported by all native implementations.
|
||||
*
|
||||
* See https://reactnative.dev/docs/asyncstorage#multimerge
|
||||
*/
|
||||
multiMerge: function (
|
||||
keyValuePairs: Array<Array<string>>,
|
||||
callback?: ?(errors: ?Array<Error>) => void,
|
||||
): Promise<void> {
|
||||
invariant(RCTAsyncStorage, 'RCTAsyncStorage not available');
|
||||
return new Promise((resolve, reject) => {
|
||||
RCTAsyncStorage.multiMerge(keyValuePairs, function (errors) {
|
||||
const error = convertErrors(errors);
|
||||
callback && callback(error);
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// Not all native implementations support merge.
|
||||
// TODO: Check whether above comment is correct. multiMerge is guaranteed to
|
||||
// exist in the module spec so we should be able to just remove this check.
|
||||
if (RCTAsyncStorage && !RCTAsyncStorage.multiMerge) {
|
||||
// $FlowFixMe[unclear-type]
|
||||
delete (AsyncStorage: any).mergeItem;
|
||||
// $FlowFixMe[unclear-type]
|
||||
delete (AsyncStorage: any).multiMerge;
|
||||
}
|
||||
|
||||
function convertErrors(
|
||||
// NOTE: The native module spec only has the Array case, but the Android
|
||||
// implementation passes a single object.
|
||||
errs: ?(
|
||||
| {message: string, key?: string}
|
||||
| Array<{message: string, key?: string}>
|
||||
),
|
||||
) {
|
||||
if (!errs) {
|
||||
return null;
|
||||
}
|
||||
return (Array.isArray(errs) ? errs : [errs]).map(e => convertError(e));
|
||||
}
|
||||
|
||||
declare function convertError(void | null): null;
|
||||
declare function convertError({message: string, key?: string}): Error;
|
||||
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
|
||||
* LTI update could not be added via codemod */
|
||||
function convertError(error) {
|
||||
if (!error) {
|
||||
return null;
|
||||
}
|
||||
const out = new Error(error.message);
|
||||
// $FlowFixMe[unclear-type]
|
||||
(out: any).key = error.key;
|
||||
return out;
|
||||
}
|
||||
|
||||
module.exports = AsyncStorage;
|
||||
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {TurboModule} from '../TurboModule/RCTExport';
|
||||
|
||||
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+getConstants: () => {};
|
||||
+multiGet: (
|
||||
keys: Array<string>,
|
||||
callback: (
|
||||
errors: ?Array<{message: string, key?: string}>,
|
||||
kvPairs: ?Array<Array<string>>,
|
||||
) => void,
|
||||
) => void;
|
||||
+multiSet: (
|
||||
kvPairs: Array<Array<string>>,
|
||||
callback: (errors: ?Array<{message: string, key?: string}>) => void,
|
||||
) => void;
|
||||
+multiMerge: (
|
||||
kvPairs: Array<Array<string>>,
|
||||
callback: (errors: ?Array<{message: string, key?: string}>) => void,
|
||||
) => void;
|
||||
+multiRemove: (
|
||||
keys: Array<string>,
|
||||
callback: (errors: ?Array<{message: string, key?: string}>) => void,
|
||||
) => void;
|
||||
+clear: (callback: (error: {message: string, key?: string}) => void) => void;
|
||||
+getAllKeys: (
|
||||
callback: (
|
||||
error: ?{message: string, key?: string},
|
||||
allKeys: ?Array<string>,
|
||||
) => void,
|
||||
) => void;
|
||||
}
|
||||
|
||||
export default (TurboModuleRegistry.get<Spec>('AsyncLocalStorage'): ?Spec);
|
||||
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {TurboModule} from '../TurboModule/RCTExport';
|
||||
|
||||
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+getConstants: () => {};
|
||||
+multiGet: (
|
||||
keys: Array<string>,
|
||||
callback: (
|
||||
errors: ?Array<{message: string, key?: string}>,
|
||||
kvPairs: ?Array<Array<string>>,
|
||||
) => void,
|
||||
) => void;
|
||||
+multiSet: (
|
||||
kvPairs: Array<Array<string>>,
|
||||
callback: (errors: ?Array<{message: string, key?: string}>) => void,
|
||||
) => void;
|
||||
+multiMerge: (
|
||||
kvPairs: Array<Array<string>>,
|
||||
callback: (errors: ?Array<{message: string, key?: string}>) => void,
|
||||
) => void;
|
||||
+multiRemove: (
|
||||
keys: Array<string>,
|
||||
callback: (errors: ?Array<{message: string, key?: string}>) => void,
|
||||
) => void;
|
||||
+clear: (callback: (error: {message: string, key?: string}) => void) => void;
|
||||
+getAllKeys: (
|
||||
callback: (
|
||||
error: ?{message: string, key?: string},
|
||||
allKeys: ?Array<string>,
|
||||
) => void,
|
||||
) => void;
|
||||
}
|
||||
|
||||
export default (TurboModuleRegistry.get<Spec>('AsyncSQLiteDBStorage'): ?Spec);
|
||||
@@ -51,7 +51,6 @@ import typeof * as AnimatedModule from './Libraries/Animated/Animated';
|
||||
import typeof Appearance from './Libraries/Utilities/Appearance';
|
||||
import typeof AppRegistry from './Libraries/ReactNative/AppRegistry';
|
||||
import typeof AppState from './Libraries/AppState/AppState';
|
||||
import typeof AsyncStorage from './Libraries/Storage/AsyncStorage';
|
||||
import typeof BackHandler from './Libraries/Utilities/BackHandler';
|
||||
import typeof Clipboard from './Libraries/Components/Clipboard/Clipboard';
|
||||
import typeof DeviceInfo from './Libraries/Utilities/DeviceInfo';
|
||||
@@ -252,16 +251,6 @@ module.exports = {
|
||||
get AppState(): AppState {
|
||||
return require('./Libraries/AppState/AppState');
|
||||
},
|
||||
// $FlowFixMe[value-as-type]
|
||||
get AsyncStorage(): AsyncStorage {
|
||||
warnOnce(
|
||||
'async-storage-moved',
|
||||
'AsyncStorage has been extracted from react-native core and will be removed in a future release. ' +
|
||||
"It can now be installed and imported from '@react-native-async-storage/async-storage' instead of 'react-native'. " +
|
||||
'See https://github.com/react-native-async-storage/async-storage',
|
||||
);
|
||||
return require('./Libraries/Storage/AsyncStorage');
|
||||
},
|
||||
get BackHandler(): BackHandler {
|
||||
return require('./Libraries/Utilities/BackHandler');
|
||||
},
|
||||
@@ -761,4 +750,19 @@ if (__DEV__) {
|
||||
);
|
||||
},
|
||||
});
|
||||
/* $FlowFixMe[prop-missing] This is intentional: Flow will error when
|
||||
* attempting to access AsyncStorage. */
|
||||
/* $FlowFixMe[invalid-export] This is intentional: Flow will error when
|
||||
* attempting to access AsyncStorage. */
|
||||
Object.defineProperty(module.exports, 'AsyncStorage', {
|
||||
configurable: true,
|
||||
get() {
|
||||
invariant(
|
||||
false,
|
||||
'AsyncStorage has been removed from react-native core. ' +
|
||||
"It can now be installed and imported from '@react-native-async-storage/async-storage' instead of 'react-native'. " +
|
||||
'See https://github.com/react-native-async-storage/async-storage',
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import * as React from 'react';
|
||||
import {
|
||||
AccessibilityInfo,
|
||||
ActionSheetIOS,
|
||||
AsyncStorage,
|
||||
Alert,
|
||||
AppState,
|
||||
AppStateStatus,
|
||||
|
||||
Vendored
-1
@@ -135,7 +135,6 @@ export * from '../Libraries/Renderer/implementations/ReactNativeRenderer';
|
||||
export * from '../Libraries/Renderer/shims/ReactNativeTypes';
|
||||
export * from '../Libraries/Settings/Settings';
|
||||
export * from '../Libraries/Share/Share';
|
||||
export * from '../Libraries/Storage/AsyncStorage';
|
||||
export * from '../Libraries/StyleSheet/PlatformColorValueTypesIOS';
|
||||
export * from '../Libraries/StyleSheet/PlatformColorValueTypes';
|
||||
export * from '../Libraries/StyleSheet/StyleSheet';
|
||||
|
||||
Reference in New Issue
Block a user