react-native-onyx 1.0.59 → 1.0.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,153 @@
1
+ import {IsEqual} from 'type-fest';
2
+ import {CollectionKeyBase, KeyValueMapping, OnyxCollection, OnyxEntry, OnyxKey, Selector} from './types';
3
+
4
+ /**
5
+ * Represents the base mapping options between an Onyx key and the component's prop.
6
+ */
7
+ type BaseMapping<TComponentProps, TOnyxProps> = {
8
+ canEvict?: boolean | ((props: Omit<TComponentProps, keyof TOnyxProps>) => boolean);
9
+ initWithStoredValues?: boolean;
10
+ };
11
+
12
+ /**
13
+ * Represents the string / function `key` mapping option between an Onyx key and the component's prop.
14
+ *
15
+ * If `key` is `string`, the type of the Onyx value that is associated with `key` must match with the type of the component's prop,
16
+ * otherwise an error will be thrown.
17
+ *
18
+ * If `key` is `function`, the return type of `key` function must be a valid Onyx key and the type of the Onyx value associated
19
+ * with `key` must match with the type of the component's prop, otherwise an error will be thrown.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * // Onyx prop with `string` key
24
+ * onyxProp: {
25
+ * key: ONYXKEYS.ACCOUNT,
26
+ * },
27
+ *
28
+ * // Onyx prop with `function` key
29
+ * onyxProp: {
30
+ * key: ({reportId}) => ONYXKEYS.ACCOUNT,
31
+ * },
32
+ * ```
33
+ */
34
+ type BaseMappingKey<
35
+ TComponentProps,
36
+ TOnyxProps,
37
+ TOnyxProp extends keyof TOnyxProps,
38
+ TOnyxKey extends OnyxKey,
39
+ TOnyxValue
40
+ > = IsEqual<TOnyxValue, TOnyxProps[TOnyxProp]> extends true
41
+ ? {
42
+ key: TOnyxKey | ((props: Omit<TComponentProps, keyof TOnyxProps>) => TOnyxKey);
43
+ }
44
+ : never;
45
+
46
+ /**
47
+ * Represents the string `key` and `selector` mapping options between an Onyx key and the component's prop.
48
+ *
49
+ * The function signature and return type of `selector` must match with the type of the component's prop,
50
+ * otherwise an error will be thrown.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * // Onyx prop with `string` key and selector
55
+ * onyxProp: {
56
+ * key: ONYXKEYS.ACCOUNT,
57
+ * selector: (value: Account | null): string => value?.id ?? '',
58
+ * },
59
+ * ```
60
+ */
61
+ type BaseMappingStringKeyAndSelector<
62
+ TComponentProps,
63
+ TOnyxProps,
64
+ TOnyxProp extends keyof TOnyxProps,
65
+ TOnyxKey extends OnyxKey
66
+ > = {
67
+ key: TOnyxKey;
68
+ selector: Selector<TOnyxKey, TOnyxProps[TOnyxProp]>;
69
+ };
70
+
71
+ /**
72
+ * Represents the function `key` and `selector` mapping options between an Onyx key and the component's prop.
73
+ *
74
+ * The function signature and return type of `selector` must match with the type of the component's prop,
75
+ * otherwise an error will be thrown.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * // Onyx prop with `function` key and selector
80
+ * onyxProp: {
81
+ * key: ({reportId}) => ONYXKEYS.ACCOUNT,
82
+ * selector: (value: Account | null) => value?.id ?? '',
83
+ * },
84
+ * ```
85
+ */
86
+ type BaseMappingFunctionKeyAndSelector<
87
+ TComponentProps,
88
+ TOnyxProps,
89
+ TOnyxProp extends keyof TOnyxProps,
90
+ TOnyxKey extends OnyxKey
91
+ > = {
92
+ key: (props: Omit<TComponentProps, keyof TOnyxProps>) => TOnyxKey;
93
+ selector: Selector<TOnyxKey, TOnyxProps[TOnyxProp]>;
94
+ };
95
+
96
+ /**
97
+ * Represents the mapping options between an Onyx key and the component's prop with all its possibilities.
98
+ */
99
+ type Mapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps, TOnyxKey extends OnyxKey> = BaseMapping<
100
+ TComponentProps,
101
+ TOnyxProps
102
+ > &
103
+ (
104
+ | BaseMappingKey<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey, OnyxEntry<KeyValueMapping[TOnyxKey]>>
105
+ | BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey>
106
+ | BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey>
107
+ );
108
+
109
+ /**
110
+ * Represents the mapping options between an Onyx collection key without suffix and the component's prop with all its possibilities.
111
+ */
112
+ type CollectionMapping<
113
+ TComponentProps,
114
+ TOnyxProps,
115
+ TOnyxProp extends keyof TOnyxProps,
116
+ TOnyxKey extends CollectionKeyBase
117
+ > = BaseMapping<TComponentProps, TOnyxProps> &
118
+ (
119
+ | BaseMappingKey<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey, OnyxCollection<KeyValueMapping[TOnyxKey]>>
120
+ | BaseMappingStringKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey>
121
+ | BaseMappingFunctionKeyAndSelector<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey>
122
+ );
123
+
124
+ /**
125
+ * Represents an union type of all the possible Onyx key mappings.
126
+ * Each `OnyxPropMapping` will be associated with its respective Onyx key, ensuring different type-safety for each object.
127
+ */
128
+ type OnyxPropMapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps> = {
129
+ [TOnyxKey in OnyxKey]: Mapping<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey>;
130
+ }[OnyxKey];
131
+
132
+ /**
133
+ * Represents an union type of all the possible Onyx collection keys without suffix mappings.
134
+ * Each `OnyxPropCollectionMapping` will be associated with its respective Onyx key, ensuring different type-safety for each object.
135
+ */
136
+ type OnyxPropCollectionMapping<TComponentProps, TOnyxProps, TOnyxProp extends keyof TOnyxProps> = {
137
+ [TOnyxKey in CollectionKeyBase]: CollectionMapping<TComponentProps, TOnyxProps, TOnyxProp, TOnyxKey>;
138
+ }[CollectionKeyBase];
139
+
140
+ /**
141
+ * This is a higher order component that provides the ability to map a state property directly to
142
+ * something in Onyx (a key/value store). That way, as soon as data in Onyx changes, the state will be set and the view
143
+ * will automatically change to reflect the new data.
144
+ */
145
+ declare function withOnyx<TComponentProps, TOnyxProps>(
146
+ mapping: {
147
+ [TOnyxProp in keyof TOnyxProps]:
148
+ | OnyxPropMapping<TComponentProps, TOnyxProps, TOnyxProp>
149
+ | OnyxPropCollectionMapping<TComponentProps, TOnyxProps, TOnyxProp>;
150
+ },
151
+ ): (component: React.ComponentType<TComponentProps>) => React.ComponentType<Omit<TComponentProps, keyof TOnyxProps>>;
152
+
153
+ export default withOnyx;
package/lib/withOnyx.js CHANGED
@@ -41,7 +41,18 @@ export default function (mapOnyxToState) {
41
41
  const key = Str.result(mapping.key, props);
42
42
  const value = Onyx.tryGetCachedValue(key, mapping);
43
43
 
44
- if (value !== undefined) {
44
+ /**
45
+ * If we have a pending merge for a key it could mean that data is being set via Onyx.merge() and someone expects a component to have this data immediately.
46
+ *
47
+ * @example
48
+ *
49
+ * Onyx.merge('report_123', value);
50
+ * Navigation.navigate(route); // Where "route" expects the "value" to be available immediately once rendered.
51
+ *
52
+ * In reality, Onyx.merge() will only update the subscriber after all merges have been batched and the previous value is retrieved via a get() (returns a promise).
53
+ * So, we won't use the cache optimization here as it will lead us to arbitrarily defer various actions in the application code.
54
+ */
55
+ if (value !== undefined && !Onyx.hasPendingMergeForKey(key)) {
45
56
  // eslint-disable-next-line no-param-reassign
46
57
  resultObj[propertyName] = value;
47
58
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "1.0.59",
3
+ "version": "1.0.61",
4
4
  "author": "Expensify, Inc.",
5
5
  "homepage": "https://expensify.com",
6
6
  "description": "State management for React Native",
@@ -31,6 +31,7 @@
31
31
  "react-native": "native.js",
32
32
  "main": "native.js",
33
33
  "browser": "web.js",
34
+ "types": "lib/index.d.ts",
34
35
  "scripts": {
35
36
  "lint": "eslint .",
36
37
  "lint-tests": "eslint tests/**",
@@ -50,6 +51,7 @@
50
51
  "@react-native-community/eslint-config": "^2.0.0",
51
52
  "@testing-library/jest-native": "^3.4.2",
52
53
  "@testing-library/react-native": "^7.0.2",
54
+ "@types/react": "^18.2.14",
53
55
  "babel-eslint": "^10.1.0",
54
56
  "babel-jest": "^26.2.2",
55
57
  "babel-loader": "^8.2.5",
@@ -68,6 +70,7 @@
68
70
  "react-native-performance": "^2.0.0",
69
71
  "react-native-quick-sqlite": "^8.0.0-beta.2",
70
72
  "react-test-renderer": "18.1.0",
73
+ "type-fest": "^3.12.0",
71
74
  "webpack": "^5.72.1",
72
75
  "webpack-cli": "^4.9.2",
73
76
  "webpack-merge": "^5.8.0"