Skip to content

Commit d15e1b3

Browse files
implementation of new hooks with options object
1 parent f41f1c6 commit d15e1b3

16 files changed

Lines changed: 100 additions & 63 deletions

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/__tests__/SplitTreatments.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ describe.each([
159159
</SplitTreatments>
160160
),
161161
({ names, attributes }) => {
162-
useSplitTreatments(names, attributes);
162+
useSplitTreatments({ names, attributes });
163163
renderTimes++;
164164
return null;
165165
}

src/__tests__/useSplitClient.test.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ test('useSplitClient must update on SDK events', () => {
4040
// Equivalent to
4141
// - Using config key and traffic type: `const { client } = useSplitClient(sdkBrowser.core.key, sdkBrowser.core.trafficType, { att1: 'att1' });`
4242
// - Disabling update props, since the wrapping SplitFactory has them enabled: `const { client } = useSplitClient(undefined, undefined, { att1: 'att1' }, { updateOnSdkReady: false, updateOnSdkReadyFromCache: false });`
43-
const { client } = useSplitClient(undefined, undefined, { att1: 'att1' });
43+
const { client } = useSplitClient({ attributes: { att1: 'att1' } });
4444
expect(client).toBe(mainClient); // Assert that the main client was retrieved.
4545
expect(client!.getAttributes()).toEqual({ att1: 'att1' }); // Assert that the client was retrieved with the provided attributes.
4646
countUseSplitClient++;
@@ -50,7 +50,7 @@ test('useSplitClient must update on SDK events', () => {
5050
{() => { countSplitClientUser2++; return null }}
5151
</SplitClient>
5252
{React.createElement(() => {
53-
const { client } = useSplitClient('user_2');
53+
const { client } = useSplitClient({ splitKey: 'user_2' });
5454
expect(client).toBe(user2Client);
5555
countUseSplitClientUser2++;
5656
return null;
@@ -59,21 +59,21 @@ test('useSplitClient must update on SDK events', () => {
5959
{() => { countSplitClientWithUpdate++; return null }}
6060
</SplitClient>
6161
{React.createElement(() => {
62-
useSplitClient(sdkBrowser.core.key, sdkBrowser.core.trafficType, undefined, { updateOnSdkUpdate: true }).client;
62+
useSplitClient({ splitKey: sdkBrowser.core.key, trafficType: sdkBrowser.core.trafficType, updateOnSdkUpdate: true }).client;
6363
countUseSplitClientWithUpdate++;
6464
return null;
6565
})}
6666
<SplitClient splitKey={'user_2'} updateOnSdkUpdate={true}>
6767
{() => { countSplitClientUser2WithUpdate++; return null }}
6868
</SplitClient>
6969
{React.createElement(() => {
70-
useSplitClient('user_2', undefined, undefined, { updateOnSdkUpdate: true });
70+
useSplitClient({ splitKey: 'user_2', updateOnSdkUpdate: true });
7171
countUseSplitClientUser2WithUpdate++;
7272
return null;
7373
})}
7474
<SplitClient splitKey={'user_2'} updateOnSdkUpdate={true}>
7575
{React.createElement(() => {
76-
const status = useSplitClient('user_2', undefined, undefined, { updateOnSdkUpdate: true });
76+
const status = useSplitClient({ splitKey: 'user_2', updateOnSdkUpdate: true });
7777
expect(status.client).toBe(user2Client);
7878

7979
// useSplitClient doesn't re-render twice if it is in the context of a SplitClient with same user key and there is a SDK event
@@ -143,7 +143,7 @@ test('useSplitClient must support changes in update props', () => {
143143
let rendersCount = 0;
144144

145145
function InnerComponent(updateOptions) {
146-
useSplitClient(undefined, undefined, undefined, updateOptions);
146+
useSplitClient(updateOptions);
147147
rendersCount++;
148148
return null;
149149
}

src/__tests__/useSplitTreatments.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,21 +51,21 @@ test('useSplitTreatments must update on SDK events', async () => {
5151
{() => { countSplitTreatments++; return null }}
5252
</SplitTreatments>
5353
{React.createElement(() => {
54-
const context = useSplitTreatments(['split_test'], { att1: 'att1' });
54+
const context = useSplitTreatments({ names: ['split_test'], attributes: { att1: 'att1' } });
5555
expect(context.client).toBe(mainClient); // Assert that the main client was retrieved.
5656
validateTreatments(context);
5757
countUseSplitTreatments++;
5858
return null;
5959
})}
6060
{React.createElement(() => {
61-
const context = useSplitTreatments(['split_test'], undefined, 'user_2');
61+
const context = useSplitTreatments({ names: ['split_test'], splitKey: 'user_2' });
6262
expect(context.client).toBe(user2Client);
6363
validateTreatments(context);
6464
countUseSplitTreatmentsUser2++;
6565
return null;
6666
})}
6767
{React.createElement(() => {
68-
const context = useSplitTreatments(['split_test'], undefined, 'user_2', { updateOnSdkUpdate: true });
68+
const context = useSplitTreatments({ names: ['split_test'], splitKey: 'user_2', updateOnSdkUpdate: true });
6969
expect(context.client).toBe(user2Client);
7070
validateTreatments(context);
7171
countUseSplitTreatmentsUser2WithUpdate++;

src/types.ts

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ export interface ISplitFactoryChildProps extends ISplitContextValues { }
102102

103103
/**
104104
* SplitFactory Props interface. These are the props accepted by SplitFactory component,
105-
* used to instantiate a factory and client instances, update the Split context, and listen for SDK events.
105+
* used to instantiate a factory and client instance, update the Split context, and listen for SDK events.
106106
*/
107107
export interface ISplitFactoryProps extends IUpdateProps {
108108

@@ -129,22 +129,15 @@ export interface ISplitFactoryProps extends IUpdateProps {
129129
}
130130

131131
/**
132-
* SplitClient Child Props interface. These are the props that the child component receives from the 'SplitClient' component.
133-
*/
134-
// @TODO remove next type (breaking-change)
135-
// eslint-disable-next-line @typescript-eslint/no-empty-interface
136-
export interface ISplitClientChildProps extends ISplitContextValues { }
137-
138-
/**
139-
* SplitClient Props interface. These are the props accepted by SplitClient component,
140-
* used to instantiate a new client instances, update the Split context, and listen for SDK events.
132+
* useSplitClient options interface. This is the options object accepted by useSplitClient hook,
133+
* used to retrieve a client instance with the Split context, and listen for SDK events.
141134
*/
142-
export interface ISplitClientProps extends IUpdateProps {
135+
export interface IUseSplitClientOptions extends IUpdateProps {
143136

144137
/**
145138
* The customer identifier.
146139
*/
147-
splitKey: SplitIO.SplitKey;
140+
splitKey?: SplitIO.SplitKey;
148141

149142
/**
150143
* Traffic type associated with the customer identifier.
@@ -156,13 +149,39 @@ export interface ISplitClientProps extends IUpdateProps {
156149
* An object of type Attributes used to evaluate the feature flags.
157150
*/
158151
attributes?: SplitIO.Attributes;
152+
}
153+
154+
/**
155+
* SplitClient Child Props interface. These are the props that the child component receives from the 'SplitClient' component.
156+
*/
157+
// @TODO remove next type (breaking-change)
158+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
159+
export interface ISplitClientChildProps extends ISplitContextValues { }
160+
161+
/**
162+
* SplitClient Props interface. These are the props accepted by SplitClient component,
163+
* used to instantiate a new client instance, update the Split context, and listen for SDK events.
164+
*/
165+
export interface ISplitClientProps extends IUseSplitClientOptions {
159166

160167
/**
161168
* Children of the SplitFactory component. It can be a functional component (child as a function) or a React element.
162169
*/
163170
children: ((props: ISplitClientChildProps) => ReactNode) | ReactNode;
164171
}
165172

173+
/**
174+
* useSplitTreatments options interface. This is the options object accepted by useSplitTreatments hook,
175+
* used to call 'client.getTreatmentsWithConfig()' and retrieve the result together with the Split context.
176+
*/
177+
export interface IUseSplitTreatmentsOptions extends IUseSplitClientOptions {
178+
179+
/**
180+
* list of feature flag names
181+
*/
182+
names: string[]
183+
}
184+
166185
/**
167186
* SplitTreatments Child Props interface. These are the props that the child component receives from the 'SplitTreatments' component.
168187
*/

src/useClient.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ import { useSplitClient } from './useSplitClient';
88
* @return A Split Client instance, or null if used outside the scope of SplitFactory
99
* @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#advanced-instantiate-multiple-sdk-clients}
1010
*/
11-
export function useClient(key?: SplitIO.SplitKey, trafficType?: string, attributes?: SplitIO.Attributes): SplitIO.IBrowserClient | null {
12-
return useSplitClient(key, trafficType, attributes).client;
11+
export function useClient(splitKey?: SplitIO.SplitKey, trafficType?: string, attributes?: SplitIO.Attributes): SplitIO.IBrowserClient | null {
12+
return useSplitClient({ splitKey, trafficType, attributes }).client;
1313
}

src/useSplitClient.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { SplitContext } from './SplitContext';
33
import { getSplitClient, initAttributes, IClientWithContext, getStatus } from './utils';
4-
import { ISplitContextValues, IUpdateProps } from './types';
4+
import { ISplitContextValues, IUseSplitClientOptions } from './types';
55

66
export const DEFAULT_UPDATE_OPTIONS = {
77
updateOnSdkUpdate: false,
@@ -17,17 +17,17 @@ export const DEFAULT_UPDATE_OPTIONS = {
1717
* @return A Split Context object
1818
* @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#advanced-instantiate-multiple-sdk-clients}
1919
*/
20-
export function useSplitClient(key?: SplitIO.SplitKey, trafficType?: string, attributes?: SplitIO.Attributes, options?: IUpdateProps): ISplitContextValues {
20+
export function useSplitClient(options?: IUseSplitClientOptions): ISplitContextValues {
2121
const {
22-
updateOnSdkReady, updateOnSdkReadyFromCache, updateOnSdkTimedout, updateOnSdkUpdate
22+
updateOnSdkReady, updateOnSdkReadyFromCache, updateOnSdkTimedout, updateOnSdkUpdate, splitKey, trafficType, attributes
2323
} = { ...DEFAULT_UPDATE_OPTIONS, ...options };
2424

2525
const context = React.useContext(SplitContext);
2626
const { client: contextClient, factory } = context;
2727

2828
let client = contextClient as IClientWithContext;
29-
if (key && factory) {
30-
client = getSplitClient(factory, key, trafficType);
29+
if (splitKey && factory) {
30+
client = getSplitClient(factory, splitKey, trafficType);
3131
}
3232
initAttributes(client, attributes);
3333

src/useSplitTreatments.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { getControlTreatmentsWithConfig } from './constants';
33
import { IClientWithContext, memoizeGetTreatmentsWithConfig } from './utils';
4-
import { ISplitTreatmentsChildProps, IUpdateProps } from './types';
4+
import { ISplitTreatmentsChildProps, IUseSplitTreatmentsOptions } from './types';
55
import { useSplitClient } from './useSplitClient';
66

77
/**
@@ -11,15 +11,16 @@ import { useSplitClient } from './useSplitClient';
1111
* @return A Split Context object extended with a TreatmentsWithConfig instance, that might contain control treatments if the client is not available or ready, or if split names do not exist.
1212
* @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#get-treatments-with-configurations}
1313
*/
14-
export function useSplitTreatments(splitNames: string[], attributes?: SplitIO.Attributes, key?: SplitIO.SplitKey, options?: IUpdateProps): ISplitTreatmentsChildProps {
15-
const context = useSplitClient(key, undefined, undefined, options);
16-
const client = context.client;
14+
export function useSplitTreatments(options: IUseSplitTreatmentsOptions): ISplitTreatmentsChildProps {
15+
const context = useSplitClient({...options, attributes: undefined });
16+
const { client, lastUpdate } = context;
17+
const { names, attributes } = options;
1718

1819
const getTreatmentsWithConfig = React.useMemo(memoizeGetTreatmentsWithConfig, []);
1920

2021
const treatments = client && (client as IClientWithContext).__getStatus().isOperational ?
21-
getTreatmentsWithConfig(client, context.lastUpdate, splitNames, attributes, { ...client.getAttributes() }) :
22-
getControlTreatmentsWithConfig(splitNames);
22+
getTreatmentsWithConfig(client, lastUpdate, names, attributes, { ...client.getAttributes() }) :
23+
getControlTreatmentsWithConfig(names);
2324

2425
return {
2526
...context,

src/useTrack.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useClient } from './useClient';
1+
import { useSplitClient } from './useSplitClient';
22

33
// no-op function that returns false
44
const noOpFalse = () => false;
@@ -10,7 +10,8 @@ const noOpFalse = () => false;
1010
* @return A track function bound to a Split client. If the client is not available, the result is a no-op function that returns false.
1111
* @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#track}
1212
*/
13-
export function useTrack(key?: SplitIO.SplitKey, trafficType?: string): SplitIO.IBrowserClient['track'] {
14-
const client = useClient(key, trafficType);
13+
export function useTrack(splitKey?: SplitIO.SplitKey, trafficType?: string): SplitIO.IBrowserClient['track'] {
14+
// All update options are false to avoid re-renders. The track method doesn't need the client to be operational.
15+
const { client } = useSplitClient({ splitKey, trafficType, updateOnSdkReady: false, updateOnSdkReadyFromCache: false });
1516
return client ? client.track.bind(client) : noOpFalse;
1617
}

src/useTreatments.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ import { useSplitTreatments } from './useSplitTreatments';
88
* @return A TreatmentsWithConfig instance, that might contain control treatments if the client is not available or ready, or if feature flag names do not exist.
99
* @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#get-treatments-with-configurations}
1010
*/
11-
export function useTreatments(featureFlagNames: string[], attributes?: SplitIO.Attributes, key?: SplitIO.SplitKey): SplitIO.TreatmentsWithConfig {
12-
return useSplitTreatments(featureFlagNames, attributes, key).treatments;
11+
export function useTreatments(featureFlagNames: string[], attributes?: SplitIO.Attributes, splitKey?: SplitIO.SplitKey): SplitIO.TreatmentsWithConfig {
12+
return useSplitTreatments({ names: featureFlagNames, attributes, splitKey }).treatments;
1313
}

0 commit comments

Comments
 (0)