Skip to content

Commit

Permalink
chore: RN provider and hooks attempt 2 (#321)
Browse files Browse the repository at this point in the history
This is a second attempt of #306 using the newly added event source.

- use StreamingProcessor and event source to fetch flags
- added LDProvider
- added hooks
- added typed variation[Detail] functions

Please read the [example
README](https://github.com/launchdarkly/js-core/blob/9d458f28625c12169df614c8d2289f9c0952cc45/packages/sdk/react-native/example/README.md#L1)
and try running the example app.

---------

Co-authored-by: LaunchDarklyReleaseBot <[email protected]>
Co-authored-by: Ryan Lamb <[email protected]>
  • Loading branch information
3 people authored Nov 30, 2023
1 parent aaaf6d1 commit a343c83
Show file tree
Hide file tree
Showing 36 changed files with 997 additions and 263 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ module.exports = {
],
'import/default': 'error',
'import/export': 'error',
'import/extensions': ['error', 'never', { json: 'always' }],
'import/no-self-import': 'error',
'import/no-cycle': 'error',
'import/no-useless-path-segments': 'error',
Expand Down
12 changes: 1 addition & 11 deletions packages/sdk/react-native/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,14 @@ yarn add @launchdarkly/react-native-client-sdk
TODO

```typescript
import { init } from '@launchdarkly/react-native-client-sdk';

// TODO
```

See the full [example app](https://github.com/launchdarkly/js-core/tree/main/packages/sdk/react-native/example).

## Developing this SDK

:information_source: You will need to setup your sdk key in the example dir. See the example [README](https://github.com/launchdarkly/js-core/blob/main/packages/sdk/react-native/example/README.md#L1).

```shell
# at js-core repo root
yarn && yarn build

# at sdk/react-native repo
yarn android | ios
```
:information_source: See the example [README](https://github.com/launchdarkly/js-core/blob/main/packages/sdk/react-native/example/README.md#L1).

## About LaunchDarkly

Expand Down
3 changes: 3 additions & 0 deletions packages/sdk/react-native/example/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ yarn-error.*

# typescript
*.tsbuildinfo

ios
android
48 changes: 11 additions & 37 deletions packages/sdk/react-native/example/App.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,18 @@
import { CLIENT_SIDE_SDK_KEY } from '@env';
import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { MOBILE_KEY } from '@env';

import { init, type LDClientImpl } from '@launchdarkly/react-native-client-sdk';
import { LDProvider, ReactNativeLDClient } from '@launchdarkly/react-native-client-sdk';

const context = { kind: 'user', key: 'test-user-1' };

export default function App() {
const [ldc, setLdc] = useState<LDClientImpl>();
const [flag, setFlag] = useState<boolean>(false);
import Welcome from './src/welcome';

useEffect(() => {
init(CLIENT_SIDE_SDK_KEY, context)
.then((c) => {
setLdc(c);
})
.catch((e) => console.log(e));
}, []);

useEffect(() => {
const f = ldc?.boolVariation('dev-test-flag', false);
setFlag(f ?? false);
}, [ldc]);
const featureClient = new ReactNativeLDClient(MOBILE_KEY);
const context = { kind: 'user', key: 'test-user-1' };

const App = () => {
return (
<View style={styles.container}>
<Text>{flag ? <>devTestFlag: {`${flag}`}</> : <>loading...</>}</Text>
</View>
<LDProvider client={featureClient} context={context}>
<Welcome />
</LDProvider>
);
}
};

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
box: {
width: 60,
height: 60,
marginVertical: 20,
},
});
export default App;
22 changes: 16 additions & 6 deletions packages/sdk/react-native/example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,29 @@

To run the example app:

1. Create a `.env` file at the same level as this README
2. Add your client-side sdk key to that `.env` file:
1. At the js-core repo root:

```shell
CLIENT_SIDE_SDK_KEY=abcdef12456
yarn && yarn build
```

3. Finally
2. Create an `.env` file at the same level as this README and add your mobile key to that `.env` file:

```shell
MOBILE_KEY=abcdef12456
```

3. Replace `dev-test-flag` with your flag key in `src/welcome.tsx`.

4. Run the app:

```shell
# Note for android, there's an issue with Flipper interfering with streaming connections
# so please run the release build. There's no such issue with ios.

# android
yarn && yarn android
yarn && yarn android-release

# ios
yarn && yarn ios
yarn && yarn ios-go
```
10 changes: 7 additions & 3 deletions packages/sdk/react-native/example/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,19 @@
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"assetBundlePatterns": ["**/*"],
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true
"supportsTablet": true,
"bundleIdentifier": "com.anonymous.reactnativeexample"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
}
},
"package": "com.anonymous.reactnativeexample"
},
"web": {
"favicon": "./assets/favicon.png"
Expand Down
14 changes: 11 additions & 3 deletions packages/sdk/react-native/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,21 @@
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android --clear",
"ios": "expo start --ios --clear",
"expo-clean": "expo prebuild --clean",
"android": "expo run:android",
"android-release": "expo run:android --variant release",
"android-go": "expo start --android --clear",
"android-log": "react-native log-android",
"ios": "expo run:ios",
"ios-release": "expo run:ios --configuration Release",
"ios-go": "expo start --ios --clear",
"ios-log": "react-native log-ios",
"web": "expo start --web --clear",
"clean": "yarn cache clean && rm -rf node_modules"
"clean": "expo prebuild --clean && yarn cache clean && rm -rf node_modules && rm -rf .expo"
},
"dependencies": {
"expo": "~49.0.16",
"expo-splash-screen": "~0.20.5",
"expo-status-bar": "~1.7.1",
"react": "18.2.0",
"react-native": "0.72.6"
Expand Down
41 changes: 41 additions & 0 deletions packages/sdk/react-native/example/src/welcome.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Button, StyleSheet, Text, View } from 'react-native';

import {
useBoolVariation,
useLDClient,
useLDDataSourceStatus,
} from '@launchdarkly/react-native-client-sdk';

export default function Welcome() {
const { error, status } = useLDDataSourceStatus();
const flag = useBoolVariation('dev-test-flag', false);
const ldc = useLDClient();

const login = () => {
ldc.identify({ kind: 'user', key: 'test-user-2' });
};

return (
<View style={styles.container}>
<Text>Welcome to LaunchDarkly</Text>
<Text>status: {status ?? 'not connected'}</Text>
{error ? <Text>error: {error.message}</Text> : null}
<Text>devTestFlag: {`${flag}`}</Text>
<Text>context: {JSON.stringify(ldc.getContext())}</Text>
<Button title="Login" onPress={login} />
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
box: {
width: 60,
height: 60,
marginVertical: 20,
},
});
2 changes: 1 addition & 1 deletion packages/sdk/react-native/example/types/env.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
declare module '@env' {
// eslint-disable-next-line import/prefer-default-export
export const CLIENT_SIDE_SDK_KEY: string;
export const MOBILE_KEY: string;
}
16 changes: 11 additions & 5 deletions packages/sdk/react-native/link-dev.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@ do
mkdir -p "$COMMON_DIR"
mkdir -p "$CLIENT_COMMON_DIR"

rsync -av dist "$SDK_DIR"
rsync -aq src "$SDK_DIR"
rsync -aq package.json "$SDK_DIR"
rsync -aq LICENSE "$SDK_DIR"
rsync -aq node_modules "$SDK_DIR"
rsync -aq src "$SDK_DIR"
rsync -av dist "$SDK_DIR"
rsync -aq node_modules/base64-js "$SDK_DIR"/node_modules
rsync -aq node_modules/event-target-shim "$SDK_DIR"/node_modules

rsync -aq ../../shared/common/dist "$COMMON_DIR"
rsync -aq ../../shared/common/src "$COMMON_DIR"
rsync -aq ../../shared/common/package.json "$COMMON_DIR"

rsync -aq ../../shared/common/ "$COMMON_DIR"
rm -rf "$CLIENT_COMMON_DIR"
rsync -aq ../../shared/sdk-client/ "$CLIENT_COMMON_DIR"
rsync -aq ../../shared/sdk-client/dist "$CLIENT_COMMON_DIR"
rsync -aq ../../shared/sdk-client/src "$CLIENT_COMMON_DIR"
rsync -aq ../../shared/sdk-client/package.json "$CLIENT_COMMON_DIR"
done
4 changes: 3 additions & 1 deletion packages/sdk/react-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"ios": "yarn ./example && yarn build && yarn ./example ios"
},
"peerDependencies": {
"react-native": "*"
"react": "*"
},
"dependencies": {
"@launchdarkly/js-client-sdk-common": "0.0.1",
Expand All @@ -50,6 +50,7 @@
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
"@types/jest": "^29.5.0",
"@types/react": "^18.2.31",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.1.0",
"eslint": "^8.45.0",
Expand All @@ -61,6 +62,7 @@
"jest": "^29.5.0",
"launchdarkly-js-test-helpers": "^2.2.0",
"prettier": "^3.0.0",
"react": "^18.2.0",
"rimraf": "^5.0.5",
"ts-jest": "^29.1.0",
"typedoc": "0.25.0",
Expand Down
23 changes: 23 additions & 0 deletions packages/sdk/react-native/src/ReactNativeLDClient.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { type LDContext } from '@launchdarkly/js-client-sdk-common';

import ReactNativeLDClient from './ReactNativeLDClient';

describe('ReactNativeLDClient', () => {
let ldc: ReactNativeLDClient;

beforeEach(() => {
ldc = new ReactNativeLDClient('mob-test', { sendEvents: false });
});

test('constructor', () => {
expect(ldc.sdkKey).toEqual('mob-test');
});

test('createStreamUriPath', () => {
const context: LDContext = { kind: 'user', key: 'test-user-key-1' };

expect(ldc.createStreamUriPath(context)).toEqual(
'/meval/eyJraW5kIjoidXNlciIsImtleSI6InRlc3QtdXNlci1rZXktMSJ9',
);
});
});
18 changes: 18 additions & 0 deletions packages/sdk/react-native/src/ReactNativeLDClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {
base64UrlEncode,
LDClientImpl,
type LDContext,
type LDOptions,
} from '@launchdarkly/js-client-sdk-common';

import platform from './platform';

export default class ReactNativeLDClient extends LDClientImpl {
constructor(sdkKey: string, options: LDOptions = {}) {
super(sdkKey, platform, options);
}

override createStreamUriPath(context: LDContext) {
return `/meval/${base64UrlEncode(JSON.stringify(context), platform.encoding!)}`;
}
}
6 changes: 6 additions & 0 deletions packages/sdk/react-native/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import useLDClient from './useLDClient';
import useLDDataSourceStatus from './useLDDataSourceStatus';

export * from './variation';

export { useLDDataSourceStatus, useLDClient };
10 changes: 10 additions & 0 deletions packages/sdk/react-native/src/hooks/useLDClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useContext } from 'react';

import { context, ReactContext } from '../provider/reactContext';

const useLDClient = () => {
const { client } = useContext<ReactContext>(context);
return client;
};

export default useLDClient;
10 changes: 10 additions & 0 deletions packages/sdk/react-native/src/hooks/useLDDataSourceStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useContext } from 'react';

import { context, ReactContext } from '../provider/reactContext';

const useLDDataSourceStatus = () => {
const { dataSource } = useContext<ReactContext>(context);
return dataSource;
};

export default useLDDataSourceStatus;
2 changes: 2 additions & 0 deletions packages/sdk/react-native/src/hooks/variation/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './useVariation';
export * from './useTypedVariation';
Loading

0 comments on commit a343c83

Please sign in to comment.