Skip to content

Commit 2c20946

Browse files
authored
Merge pull request #185 from sendbird/feat/migrate-store
feat(CLNP-3879): support mmkv storage and deprecate an async storage
2 parents 0e32587 + c4dcc0c commit 2c20946

File tree

23 files changed

+3685
-1399
lines changed

23 files changed

+3685
-1399
lines changed

docs-validation/1_introduction/SendYourFirstMessage.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,15 @@ export const platformServices: SendbirdUIKitContainerProps['platformServices'] =
6161
* {@link https://sendbird.com/docs/chat/uikit/v3/react-native/introduction/send-first-message#2-get-started-3-step-5-wrap-your-app-in-sendbirduikitcontainer}
6262
* */
6363
import { SendbirdUIKitContainer } from '@sendbird/uikit-react-native';
64-
import AsyncStorage from '@react-native-async-storage/async-storage';
64+
import { MMKV } from 'react-native-mmkv';
65+
66+
const mmkv = new MMKV();
6567

6668
const App = () => {
6769
return (
6870
<SendbirdUIKitContainer
6971
appId={'APP_ID'}
70-
chatOptions={{ localCacheStorage: AsyncStorage }}
72+
chatOptions={{ localCacheStorage: mmkv }}
7173
platformServices={platformServices}
7274
>
7375
{/* Rest of your app */}
@@ -186,7 +188,7 @@ const App2 = () => {
186188
return (
187189
<SendbirdUIKitContainer
188190
appId={'APP_ID'}
189-
chatOptions={{ localCacheStorage: AsyncStorage }}
191+
chatOptions={{ localCacheStorage: mmkv }}
190192
platformServices={platformServices}
191193
>
192194
<Navigation />

docs-validation/package.json

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,24 @@
88
"clean": "del lib"
99
},
1010
"dependencies": {
11-
"@bam.tech/react-native-image-resizer": "^3.0.4",
12-
"@react-native-async-storage/async-storage": "^1.15.17",
13-
"@react-native-camera-roll/camera-roll": "^5.4.0",
14-
"@react-native-clipboard/clipboard": "^1.8.5",
11+
"@bam.tech/react-native-image-resizer": "^3.0.10",
12+
"@react-native-camera-roll/camera-roll": "^7.8.1",
13+
"@react-native-clipboard/clipboard": "^1.14.1",
1514
"@react-native-firebase/messaging": "^14.7.0",
16-
"@react-navigation/native": "^6.0.6",
17-
"@react-navigation/native-stack": "^6.7.0",
18-
"@sendbird/chat": "^4.10.7",
15+
"@react-navigation/native": "^6.1.17",
16+
"@react-navigation/native-stack": "^6.10.0",
17+
"@sendbird/chat": "^4.12.9",
1918
"react": "18.2.0",
2019
"react-native": "0.74.3",
20+
"react-native-audio-recorder-player": "^3.6.10",
2121
"react-native-create-thumbnail": "^2.0.0",
22-
"react-native-document-picker": "^8.0.0",
23-
"react-native-file-access": "^2.5.0",
24-
"react-native-image-picker": "^4.7.3",
25-
"react-native-permissions": "^3.6.0",
26-
"react-native-safe-area-context": "^3.3.2",
27-
"react-native-video": "^5.2.0"
22+
"react-native-document-picker": "^9.3.0",
23+
"react-native-file-access": "^3.1.0",
24+
"react-native-image-picker": "^7.1.2",
25+
"react-native-mmkv": "^2.12.2",
26+
"react-native-permissions": "^3.10.1",
27+
"react-native-safe-area-context": "^4.10.8",
28+
"react-native-video": "^6.3.0"
2829
},
2930
"devDependencies": {
3031
"@babel/core": "^7.12.9",

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@
6060
"react": "18.2.0",
6161
"react-native": "0.74.3",
6262
"react-native-builder-bob": "^0.18.2",
63-
"react-native-fast-image": "^8.5.11",
64-
"react-native-safe-area-context": "^3.3.2",
63+
"react-native-fast-image": "^8.6.3",
64+
"react-native-safe-area-context": "^4.10.8",
6565
"react-test-renderer": "^18.3.1",
6666
"typedoc": "^0.25.3",
6767
"typescript": "5.2.2",
@@ -98,7 +98,7 @@
9898
]
9999
},
100100
"resolutions": {
101-
"@sendbird/chat": "4.11.3",
101+
"@sendbird/chat": "4.12.9",
102102
"@types/react": "^18"
103103
}
104104
}

packages/uikit-chat-hooks/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"typescript": "5.2.2"
5656
},
5757
"peerDependencies": {
58-
"@sendbird/chat": "^4.10.7",
58+
"@sendbird/chat": "^4.12.9",
5959
"react": ">=16.13.1"
6060
},
6161
"react-native-builder-bob": {

packages/uikit-react-native-foundation/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@
5656
"react": "18.2.0",
5757
"react-native": "0.74.3",
5858
"react-native-builder-bob": "^0.18.0",
59-
"react-native-fast-image": "^8.5.11",
60-
"react-native-safe-area-context": "^3.3.2",
59+
"react-native-fast-image": "^8.6.3",
60+
"react-native-safe-area-context": "^4.10.8",
6161
"typescript": "5.2.2"
6262
},
6363
"peerDependencies": {

packages/uikit-react-native/README.md

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,15 @@ UIKit for React-Native can be installed through either `yarn` or `npm`
4646

4747
**Install dependencies**
4848

49-
> Note: If you are using `react-native` version `0.72` or higher, you don't need to install `@sendbird/react-native-scrollview-enhancer`.
49+
> Note: If you are using `react-native` version `0.71` or lower, you should install `@sendbird/react-native-scrollview-enhancer`.
5050
5151
```sh
5252
npm install @sendbird/uikit-react-native \
5353
@sendbird/chat \
54-
@sendbird/react-native-scrollview-enhancer \
5554
date-fns \
5655
react-native-safe-area-context \
5756
@react-native-community/netinfo \
58-
@react-native-async-storage/async-storage
57+
react-native-mmkv
5958
```
6059

6160
**Linking native modules**
@@ -116,7 +115,7 @@ const App = () => {
116115
<SendbirdUIKitContainer
117116
appId={'APP_ID'}
118117
chatOptions={{
119-
localCacheStorage: AsyncStorage,
118+
localCacheStorage: MMKV,
120119
}}
121120
platformServices={{
122121
file: FileService,
@@ -257,45 +256,30 @@ const expoPlatformServices = {
257256
You can implement Local caching easily.
258257

259258
```shell
260-
npm i @react-native-async-storage/async-storage
259+
npm i react-native-mmkv
261260
npx pod-install
262261
```
263262

264263
```tsx
265-
import AsyncStorage from '@react-native-async-storage/async-storage';
264+
import { MMKV } from 'react-native-mmkv';
266265

267266
import { SendbirdUIKitContainer } from '@sendbird/uikit-react-native';
268267

268+
const mmkv = new MMKV();
269269
const App = () => {
270-
return <SendbirdUIKitContainer chatOptions={{ localCacheStorage: AsyncStorage }}>{/* ... */}</SendbirdUIKitContainer>;
270+
return <SendbirdUIKitContainer chatOptions={{ localCacheStorage: mmkv }}>{/* ... */}</SendbirdUIKitContainer>;
271271
};
272272
```
273273

274-
Or you can use storage you are using instead of `AsyncStorage` (e.g. [`react-native-mmkv`](https://github.com/mrousavy/react-native-mmkv))
274+
Or you can use `AsyncStorage` instead of `MMKV`, but it has been deprecated.
275275

276276
```tsx
277-
import { MMKV } from 'react-native-mmkv';
277+
import { AsyncStorage } from '@react-native-async-storage/async-storage';
278278

279-
import { LocalCacheStorage, SendbirdUIKitContainer } from '@sendbird/uikit-react-native';
280-
281-
const mmkvStorage = new MMKV();
282-
const localCacheStorage: LocalCacheStorage = {
283-
async getAllKeys() {
284-
return mmkvStorage.getAllKeys();
285-
},
286-
async setItem(key: string, value: string) {
287-
return mmkvStorage.set(key, value);
288-
},
289-
async getItem(key: string) {
290-
return mmkvStorage.getString(key) ?? null;
291-
},
292-
async removeItem(key: string) {
293-
return mmkvStorage.delete(key);
294-
},
295-
};
279+
import { SendbirdUIKitContainer } from '@sendbird/uikit-react-native';
296280

297281
const App = () => {
298-
return <SendbirdUIKitContainer chatOptions={{ localCacheStorage }}>{/* ... */}</SendbirdUIKitContainer>;
282+
return <SendbirdUIKitContainer chatOptions={{ localCacheStorage: AsyncStorage }}>{/* ... */}</SendbirdUIKitContainer>;
299283
};
300284
```
301285

packages/uikit-react-native/package.json

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,14 @@
6767
},
6868
"devDependencies": {
6969
"@bam.tech/react-native-image-resizer": "^3.0.4",
70-
"@react-native-camera-roll/camera-roll": "^5.4.0",
71-
"@react-native-clipboard/clipboard": "^1.8.5",
72-
"@react-native-community/netinfo": "^9.3.0",
70+
"@react-native-async-storage/async-storage": "^1.17.6",
71+
"@react-native-camera-roll/camera-roll": "^7.8.1",
72+
"@react-native-clipboard/clipboard": "^1.14.1",
73+
"@react-native-community/netinfo": "^11.3.2",
7374
"@react-native-firebase/app": "^14.4.0",
7475
"@react-native-firebase/messaging": "^14.4.0",
7576
"@types/react": "*",
7677
"@types/react-native": "*",
77-
"@types/react-native-video": "^5.0.14",
7878
"date-fns": "^2.28.0",
7979
"expo-av": "^13.2.1",
8080
"expo-clipboard": "^4.1.2",
@@ -90,24 +90,26 @@
9090
"js-convert-case": "^4.2.0",
9191
"react": "18.2.0",
9292
"react-native": "0.74.3",
93-
"react-native-audio-recorder-player": "^3.6.0",
93+
"react-native-audio-recorder-player": "^3.6.10",
9494
"react-native-builder-bob": "^0.18.0",
9595
"react-native-create-thumbnail": "^2.0.0",
96-
"react-native-document-picker": "^8.0.0",
97-
"react-native-file-access": "^2.5.0",
98-
"react-native-image-picker": "^4.7.1",
99-
"react-native-permissions": "^3.6.0",
100-
"react-native-safe-area-context": "^3.3.2",
101-
"react-native-video": "^5.2.0",
96+
"react-native-document-picker": "^9.3.0",
97+
"react-native-file-access": "^3.1.0",
98+
"react-native-image-picker": "^7.1.2",
99+
"react-native-mmkv": "^2.12.2",
100+
"react-native-permissions": "^3.10.1",
101+
"react-native-safe-area-context": "^4.10.8",
102+
"react-native-video": "^6.3.0",
102103
"typescript": "5.2.2"
103104
},
104105
"peerDependencies": {
105106
"@bam.tech/react-native-image-resizer": ">=3.0.0",
107+
"@react-native-async-storage/async-storage": "^1.17.6",
106108
"@react-native-camera-roll/camera-roll": ">=5.0.0",
107109
"@react-native-clipboard/clipboard": ">=1.8.5",
108110
"@react-native-community/netinfo": ">=9.3.0",
109111
"@react-native-firebase/messaging": ">=14.4.0",
110-
"@sendbird/chat": "^4.10.7",
112+
"@sendbird/chat": "^4.12.9",
111113
"@sendbird/react-native-scrollview-enhancer": "*",
112114
"date-fns": ">=2.28.0",
113115
"expo-av": ">=12.0.4",
@@ -125,6 +127,7 @@
125127
"react-native-document-picker": ">=8.0.0",
126128
"react-native-file-access": ">=2.4.3",
127129
"react-native-image-picker": ">=4.7.1",
130+
"react-native-mmkv": "^2.0.0",
128131
"react-native-permissions": ">=3.6.0",
129132
"react-native-safe-area-context": ">=3.3.2",
130133
"react-native-video": ">=5.2.0"
@@ -133,6 +136,9 @@
133136
"@bam.tech/react-native-image-resizer": {
134137
"optional": true
135138
},
139+
"@react-native-async-storage/async-storage": {
140+
"optional": true
141+
},
136142
"@react-native-camera-roll/camera-roll": {
137143
"optional": true
138144
},

packages/uikit-react-native/src/containers/SendbirdUIKitContainer.tsx

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import type { AsyncStorageStatic } from '@react-native-async-storage/async-storage';
12
import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
23
import { Platform } from 'react-native';
4+
import type { MMKV } from 'react-native-mmkv';
35
import { SafeAreaProvider } from 'react-native-safe-area-context';
46

57
import SendbirdChat, { DeviceOsPlatform, SendbirdChatParams, SendbirdPlatform, SendbirdProduct } from '@sendbird/chat';
@@ -15,15 +17,17 @@ import {
1517
UIKitThemeProvider,
1618
} from '@sendbird/uikit-react-native-foundation';
1719
import { SBUConfig, UIKitConfigProvider } from '@sendbird/uikit-tools';
18-
import type {
20+
import {
21+
Logger,
22+
NOOP,
1923
PartialDeep,
2024
SendbirdChatSDK,
2125
SendbirdGroupChannel,
2226
SendbirdGroupChannelCreateParams,
2327
SendbirdMember,
2428
SendbirdUser,
29+
useIsFirstMount,
2530
} from '@sendbird/uikit-utils';
26-
import { NOOP, useIsFirstMount } from '@sendbird/uikit-utils';
2731

2832
import { LocalizationContext, LocalizationProvider } from '../contexts/LocalizationCtx';
2933
import { PlatformServiceProvider } from '../contexts/PlatformServiceCtx';
@@ -50,7 +54,7 @@ import type {
5054
PlayerServiceInterface,
5155
RecorderServiceInterface,
5256
} from '../platform/types';
53-
import type { ErrorBoundaryProps, LocalCacheStorage } from '../types';
57+
import { ErrorBoundaryProps, LocalCacheStorage } from '../types';
5458
import VERSION from '../version';
5559
import InternalErrorBoundaryContainer from './InternalErrorBoundaryContainer';
5660

@@ -78,13 +82,13 @@ const chatOmitKeys = [
7882
'appVersion',
7983
'localCacheEnabled',
8084
'useAsyncStorageStore',
85+
'useMMKVStorageStore',
8186
] as const;
8287
function sanitizeChatOptions<T extends Record<string, unknown>>(chatOptions: T): T {
8388
const opts = { ...chatOptions };
8489
chatOmitKeys.forEach((key) => delete opts[key]);
8590
return opts;
8691
}
87-
8892
export type SendbirdUIKitContainerProps = React.PropsWithChildren<{
8993
appId: string;
9094
platformServices: {
@@ -95,11 +99,11 @@ export type SendbirdUIKitContainerProps = React.PropsWithChildren<{
9599
player: PlayerServiceInterface;
96100
recorder: RecorderServiceInterface;
97101
};
98-
chatOptions: {
99-
localCacheStorage: LocalCacheStorage;
100-
onInitialized?: (sdkInstance: SendbirdChatSDK) => SendbirdChatSDK;
101-
} & Partial<ChatOmittedInitParams> &
102-
Partial<ChatRelatedFeaturesInUIKit>;
102+
chatOptions: Partial<ChatOmittedInitParams> &
103+
Partial<ChatRelatedFeaturesInUIKit> & {
104+
onInitialized?: (sdkInstance: SendbirdChatSDK) => SendbirdChatSDK;
105+
localCacheStorage: LocalCacheStorage;
106+
};
103107
uikitOptions?: PartialDeep<{
104108
common: SBUConfig['common'];
105109
groupChannel: Omit<SBUConfig['groupChannel']['channel'], 'enableReactionsSupergroup'> & {
@@ -162,6 +166,10 @@ const SendbirdUIKitContainer = (props: SendbirdUIKitContainerProps) => {
162166

163167
if (!chatOptions.localCacheStorage) {
164168
throw new Error('SendbirdUIKitContainer: chatOptions.localCacheStorage is required');
169+
} else if ('getItem' in chatOptions.localCacheStorage) {
170+
Logger.warn(
171+
'SendbirdUIKitContainer: localCacheStorage for `AsyncStorage` is deprecated. Please use `MMKV` instead.',
172+
);
165173
}
166174

167175
const defaultStringSet = localization?.stringSet ?? StringSetEn;
@@ -171,7 +179,7 @@ const SendbirdUIKitContainer = (props: SendbirdUIKitContainerProps) => {
171179

172180
const [internalStorage] = useState(() => new InternalLocalCacheStorage(chatOptions.localCacheStorage));
173181
const [sdkInstance, setSdkInstance] = useState<SendbirdChatSDK>(() => {
174-
const sendbird = initializeSendbird(appId, { internalStorage, ...sanitizeChatOptions(chatOptions) });
182+
const sendbird = initializeSendbird(appId, sanitizeChatOptions(chatOptions));
175183
unsubscribes.current = sendbird.unsubscribes;
176184
return sendbird.chatSDK;
177185
});
@@ -183,7 +191,7 @@ const SendbirdUIKitContainer = (props: SendbirdUIKitContainerProps) => {
183191

184192
useLayoutEffect(() => {
185193
if (!isFirstMount) {
186-
const sendbird = initializeSendbird(appId, { internalStorage, ...sanitizeChatOptions(chatOptions) });
194+
const sendbird = initializeSendbird(appId, sanitizeChatOptions(chatOptions));
187195
setSdkInstance(sendbird.chatSDK);
188196
unsubscribes.current = sendbird.unsubscribes;
189197
}
@@ -288,21 +296,23 @@ const SendbirdUIKitContainer = (props: SendbirdUIKitContainerProps) => {
288296
};
289297

290298
interface InitOptions extends ChatOmittedInitParams {
291-
internalStorage: InternalLocalCacheStorage;
299+
localCacheStorage: LocalCacheStorage;
292300
onInitialized?: (sdk: SendbirdChatSDK) => SendbirdChatSDK;
293301
}
294302
const initializeSendbird = (appId: string, options: InitOptions) => {
295303
let chatSDK: SendbirdChatSDK;
296304
const unsubscribes: Array<() => void> = [];
297-
const { internalStorage, onInitialized, ...chatInitParams } = options;
305+
const { localCacheStorage, onInitialized, ...chatInitParams } = options;
298306

307+
const isMMKVStorage = 'getString' in localCacheStorage;
299308
chatSDK = SendbirdChat.init({
300309
...chatInitParams,
301310
appId,
302311
newInstance: true,
303312
modules: [new GroupChannelModule(), new OpenChannelModule()],
304313
localCacheEnabled: true,
305-
useAsyncStorageStore: internalStorage as never,
314+
useMMKVStorageStore: isMMKVStorage ? (localCacheStorage as MMKV) : undefined,
315+
useAsyncStorageStore: !isMMKVStorage ? (localCacheStorage as AsyncStorageStatic) : undefined,
306316
});
307317

308318
if (onInitialized) {

packages/uikit-react-native/src/libs/EmojiManager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { SendbirdEmoji, SendbirdEmojiCategory, SendbirdEmojiContainer } from '@sendbird/uikit-utils';
22

3-
import type { LocalCacheStorage } from '../types';
3+
import type { AsyncLocalCacheStorage } from '../types';
44
import InternalLocalCacheStorage from './InternalLocalCacheStorage';
55

6-
class MemoryStorage implements LocalCacheStorage {
6+
class MemoryStorage implements AsyncLocalCacheStorage {
77
_data: Record<string, string> = {};
88

99
async getAllKeys(): Promise<readonly string[] | string[]> {

0 commit comments

Comments
 (0)