From 2b100b3d4ea48f785c5278239011876c6cb304a8 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 9 Apr 2025 11:16:34 -0300 Subject: [PATCH 1/7] Support default options in the SplitFactoryProvider to share via context --- src/SplitFactoryProvider.tsx | 8 +++++- src/types.ts | 56 ++++++++++++++++++------------------ src/useSplitClient.ts | 7 ++--- 3 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/SplitFactoryProvider.tsx b/src/SplitFactoryProvider.tsx index 219a0f3..d9e839e 100644 --- a/src/SplitFactoryProvider.tsx +++ b/src/SplitFactoryProvider.tsx @@ -62,7 +62,13 @@ export function SplitFactoryProvider(props: ISplitFactoryProviderProps) { }, [config, propFactory, factory]); return ( - + {props.children} ); diff --git a/src/types.ts b/src/types.ts index 6fb4f8a..3697ac9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -39,33 +39,6 @@ export interface ISplitStatus { lastUpdate: number; } -/** - * Split Context Value interface. It is used to define the value types of Split Context - */ -export interface ISplitContextValues extends ISplitStatus { - - /** - * Split factory instance. - * - * NOTE: This property is available for accessing factory methods not covered by the library hooks, - * such as Logging configuration and User Consent. - * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#logging}), - * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#user-consent} - */ - factory?: SplitIO.IBrowserSDK; - - /** - * Split client instance. - * - * NOTE: This property is not recommended for direct use, as better alternatives are available: - * - `useSplitTreatments` hook to evaluate feature flags. - * - `useTrack` hook to track events. - * - * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#2-instantiate-the-sdk-and-create-a-new-split-client} - */ - client?: SplitIO.IBrowserClient; -} - /** * Update Props interface. It defines the props used to configure what SDK events are listened to update the component. */ @@ -101,6 +74,33 @@ export interface IUpdateProps { updateOnSdkReadyFromCache?: boolean; } +/** + * Split Context Value interface. It is used to define the value types of Split Context + */ +export interface ISplitContextValues extends ISplitStatus, IUpdateProps { + + /** + * Split factory instance. + * + * NOTE: This property is available for accessing factory methods not covered by the library hooks, + * such as Logging configuration and User Consent. + * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#logging}), + * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#user-consent} + */ + factory?: SplitIO.IBrowserSDK; + + /** + * Split client instance. + * + * NOTE: This property is not recommended for direct use, as better alternatives are available: + * - `useSplitTreatments` hook to evaluate feature flags. + * - `useTrack` hook to track events. + * + * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#2-instantiate-the-sdk-and-create-a-new-split-client} + */ + client?: SplitIO.IBrowserClient; +} + /** * Props interface for components wrapped by the `withSplitFactory` HOC. These props are provided by the HOC to the wrapped component. * @@ -112,7 +112,7 @@ export interface ISplitFactoryChildProps extends ISplitContextValues { } * SplitFactoryProvider Props interface. These are the props accepted by the `SplitFactoryProvider` component, * used to instantiate a factory and provide it to the Split Context. */ -export interface ISplitFactoryProviderProps { +export interface ISplitFactoryProviderProps extends IUpdateProps { /** * Config object used to instantiate a Split factory. diff --git a/src/useSplitClient.ts b/src/useSplitClient.ts index d9344af..9aee6b5 100644 --- a/src/useSplitClient.ts +++ b/src/useSplitClient.ts @@ -24,12 +24,11 @@ export const DEFAULT_UPDATE_OPTIONS = { * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#advanced-instantiate-multiple-sdk-clients} */ export function useSplitClient(options?: IUseSplitClientOptions): ISplitContextValues { - const { - updateOnSdkReady, updateOnSdkReadyFromCache, updateOnSdkTimedout, updateOnSdkUpdate, splitKey, attributes - } = { ...DEFAULT_UPDATE_OPTIONS, ...options }; - const context = useSplitContext(); const { client: contextClient, factory } = context; + const { + updateOnSdkReady, updateOnSdkReadyFromCache, updateOnSdkTimedout, updateOnSdkUpdate, splitKey, attributes + } = { ...DEFAULT_UPDATE_OPTIONS, ...context, ...options }; // @TODO Move `getSplitClient` side effects and reduce the function cognitive complexity // @TODO Once `SplitClient` is removed, which updates the context, simplify next line as `const client = factory ? getSplitClient(factory, splitKey) : undefined;` From e5d1968a7e19d796b49609347be975b39718e030 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Wed, 9 Apr 2025 14:49:12 -0300 Subject: [PATCH 2/7] SplitClient default options --- src/SplitClient.tsx | 8 +++++++- src/__tests__/SplitTreatments.test.tsx | 10 +++++----- src/types.ts | 20 +++++++++++--------- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/SplitClient.tsx b/src/SplitClient.tsx index fd146ae..832f916 100644 --- a/src/SplitClient.tsx +++ b/src/SplitClient.tsx @@ -17,7 +17,13 @@ export function SplitClient(props: ISplitClientProps) { const context = useSplitClient(props); return ( - + { typeof children === 'function' ? children(context) : diff --git a/src/__tests__/SplitTreatments.test.tsx b/src/__tests__/SplitTreatments.test.tsx index 4ff0a78..cf21ea4 100644 --- a/src/__tests__/SplitTreatments.test.tsx +++ b/src/__tests__/SplitTreatments.test.tsx @@ -385,7 +385,7 @@ describe.each([ }); expect(renderTimesComp1).toBe(2); - expect(renderTimesComp2).toBe(2); // updateOnSdkReadyFromCache === false, in second component + expect(renderTimesComp2).toBe(1); // updateOnSdkReadyFromCache === false, in second component act(() => { (outerFactory as any).client().__emitter__.emit(Event.SDK_READY_TIMED_OUT); @@ -393,7 +393,7 @@ describe.each([ }); expect(renderTimesComp1).toBe(3); - expect(renderTimesComp2).toBe(3); + expect(renderTimesComp2).toBe(2); act(() => { (outerFactory as any).client().__emitter__.emit(Event.SDK_READY); @@ -401,7 +401,7 @@ describe.each([ }); expect(renderTimesComp1).toBe(3); // updateOnSdkReady === false, in first component - expect(renderTimesComp2).toBe(4); + expect(renderTimesComp2).toBe(3); act(() => { (outerFactory as any).client().__emitter__.emit(Event.SDK_UPDATE); @@ -409,9 +409,9 @@ describe.each([ }); expect(renderTimesComp1).toBe(4); - expect(renderTimesComp2).toBe(5); + expect(renderTimesComp2).toBe(4); expect(outerFactory.client().getTreatmentsWithConfig).toBeCalledTimes(3); // renderTimes - 1, for the 1st render where SDK is not operational - expect(outerFactory.client('user2').getTreatmentsWithConfig).toBeCalledTimes(4); // idem + expect(outerFactory.client('user2').getTreatmentsWithConfig).toBeCalledTimes(3); // idem }); it('rerenders and re-evaluates feature flags if client attributes changes.', (done) => { diff --git a/src/types.ts b/src/types.ts index 3697ac9..ef5ead3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -34,7 +34,9 @@ export interface ISplitStatus { isDestroyed: boolean; /** - * Indicates when was the last status event, either `SDK_READY`, `SDK_READY_FROM_CACHE`, `SDK_READY_TIMED_OUT` or `SDK_UPDATE`. + * `lastUpdate` indicates when the most recent status event was emitted. This timestamp is only updated for events that are being listened to, + * configured via the `updateOnSdkReady` option for `SDK_READY` event, `updateOnSdkReadyFromCache` for `SDK_READY_FROM_CACHE` event, + * `updateOnSdkTimedout` for `SDK_READY_TIMED_OUT` event, and `updateOnSdkUpdate` for `SDK_UPDATE` event. */ lastUpdate: number; } @@ -45,29 +47,29 @@ export interface ISplitStatus { export interface IUpdateProps { /** - * `updateOnSdkUpdate` indicates if the component will update (i.e., re-render) in case of an `SDK_UPDATE` event. - * If `true`, components consuming the context (such as `SplitClient` and `SplitTreatments`) will re-render on `SDK_UPDATE`. + * `updateOnSdkUpdate` indicates if the hook or component will update (i.e., re-render) in case of an `SDK_UPDATE` event. + * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_UPDATE`. * It's value is `true` by default. */ updateOnSdkUpdate?: boolean; /** - * `updateOnSdkTimedout` indicates if the component will update (i.e., re-render) in case of a `SDK_READY_TIMED_OUT` event. - * If `true`, components consuming the context (such as `SplitClient` and `SplitTreatments`) will re-render on `SDK_READY_TIMED_OUT`. + * `updateOnSdkTimedout` indicates if the hook or component will update (i.e., re-render) in case of a `SDK_READY_TIMED_OUT` event. + * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_READY_TIMED_OUT`. * It's value is `true` by default. */ updateOnSdkTimedout?: boolean; /** - * `updateOnSdkReady` indicates if the component will update (i.e., re-render) in case of a `SDK_READY` event. - * If `true`, components consuming the context (such as `SplitClient` and `SplitTreatments`) will re-render on `SDK_READY`. + * `updateOnSdkReady` indicates if the hook or component will update (i.e., re-render) in case of a `SDK_READY` event. + * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_READY`. * It's value is `true` by default. */ updateOnSdkReady?: boolean; /** - * `updateOnSdkReadyFromCache` indicates if the component will update (i.e., re-render) in case of a `SDK_READY_FROM_CACHE` event. - * If `true`, components consuming the context (such as `SplitClient` and `SplitTreatments`) will re-render on `SDK_READY_FROM_CACHE`. + * `updateOnSdkReadyFromCache` indicates if the hook or component will update (i.e., re-render) in case of a `SDK_READY_FROM_CACHE` event. + * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_READY_FROM_CACHE`. * This params is only relevant when using `'LOCALSTORAGE'` as storage type, since otherwise the event is never emitted. * It's value is `true` by default. */ From 9d603efb5cb2e988a39180a19a9eb6d0343ef962 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Fri, 11 Apr 2025 18:06:01 -0300 Subject: [PATCH 3/7] Handle undefined values --- src/SplitClient.tsx | 8 ++++---- src/useSplitClient.ts | 17 ++++++----------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/SplitClient.tsx b/src/SplitClient.tsx index 832f916..4715d67 100644 --- a/src/SplitClient.tsx +++ b/src/SplitClient.tsx @@ -19,10 +19,10 @@ export function SplitClient(props: ISplitClientProps) { return ( { typeof children === 'function' ? diff --git a/src/useSplitClient.ts b/src/useSplitClient.ts index 9aee6b5..3b3e217 100644 --- a/src/useSplitClient.ts +++ b/src/useSplitClient.ts @@ -3,13 +3,6 @@ import { useSplitContext } from './SplitContext'; import { getSplitClient, initAttributes, getStatus } from './utils'; import { ISplitContextValues, IUseSplitClientOptions } from './types'; -export const DEFAULT_UPDATE_OPTIONS = { - updateOnSdkUpdate: true, - updateOnSdkTimedout: true, - updateOnSdkReady: true, - updateOnSdkReadyFromCache: true, -}; - /** * `useSplitClient` is a hook that returns an Split Context object with the client and its status corresponding to the provided key. * @@ -23,12 +16,14 @@ export const DEFAULT_UPDATE_OPTIONS = { * * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#advanced-instantiate-multiple-sdk-clients} */ -export function useSplitClient(options?: IUseSplitClientOptions): ISplitContextValues { +export function useSplitClient(options: IUseSplitClientOptions = {}): ISplitContextValues { const context = useSplitContext(); const { client: contextClient, factory } = context; - const { - updateOnSdkReady, updateOnSdkReadyFromCache, updateOnSdkTimedout, updateOnSdkUpdate, splitKey, attributes - } = { ...DEFAULT_UPDATE_OPTIONS, ...context, ...options }; + const { splitKey, attributes } = options; + const updateOnSdkReady = options.updateOnSdkReady ?? context.updateOnSdkReady; + const updateOnSdkReadyFromCache = options.updateOnSdkReadyFromCache ?? context.updateOnSdkReadyFromCache; + const updateOnSdkTimedout = options.updateOnSdkTimedout ?? context.updateOnSdkTimedout; + const updateOnSdkUpdate = options.updateOnSdkUpdate ?? context.updateOnSdkUpdate; // @TODO Move `getSplitClient` side effects and reduce the function cognitive complexity // @TODO Once `SplitClient` is removed, which updates the context, simplify next line as `const client = factory ? getSplitClient(factory, splitKey) : undefined;` From 816a9875115fde0aea71788115cd5abbf08efe26 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 14 Apr 2025 00:14:40 -0300 Subject: [PATCH 4/7] Polishing and tests --- CHANGES.txt | 3 ++- src/SplitFactoryProvider.tsx | 10 ++++---- src/__tests__/SplitClient.test.tsx | 27 +++++++++++++++++++++- src/__tests__/testUtils/utils.tsx | 8 +++++-- src/__tests__/useSplitClient.test.tsx | 27 +++++++++++++++++++--- src/__tests__/useSplitManager.test.tsx | 6 +++-- src/__tests__/withSplitTreatments.test.tsx | 8 ++----- src/useSplitClient.ts | 14 ++++++----- 8 files changed, 77 insertions(+), 26 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 38b897c..babefc0 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ -2.1.2 (April XX, 2025) +2.2.0 (April XX, 2025) + - Added `updateOnSdkUpdate`, `updateOnSdkReady`, `updateOnSdkReadyFromCache` and `updateOnSdkTimedout` props to the `SplitFactoryProvider` component to overwrite the default value (`true`) of the `updateOnSdk` options in the `useSplitClient` and `useSplitTreatments` hooks. - Updated development dependencies to use React v19 and TypeScript v4.5.5 to test compatibility and avoid type conflicts when using the SDK with React v19 types. 2.1.1 (April 9, 2025) diff --git a/src/SplitFactoryProvider.tsx b/src/SplitFactoryProvider.tsx index d9e839e..4d2d26e 100644 --- a/src/SplitFactoryProvider.tsx +++ b/src/SplitFactoryProvider.tsx @@ -27,7 +27,10 @@ import { SplitFactory } from '@splitsoftware/splitio/client'; * @see {@link https://help.split.io/hc/en-us/articles/360038825091-React-SDK#2-instantiate-the-sdk-and-create-a-new-split-client} */ export function SplitFactoryProvider(props: ISplitFactoryProviderProps) { - const { config, factory: propFactory, attributes } = props; + const { + config, factory: propFactory, attributes, + updateOnSdkReady = true, updateOnSdkReadyFromCache = true, updateOnSdkTimedout = true, updateOnSdkUpdate = true + } = props; const factory = React.useMemo void }>(() => { return propFactory ? @@ -64,10 +67,7 @@ export function SplitFactoryProvider(props: ISplitFactoryProviderProps) { return ( {props.children} diff --git a/src/__tests__/SplitClient.test.tsx b/src/__tests__/SplitClient.test.tsx index 19fbb06..2d1bf1b 100644 --- a/src/__tests__/SplitClient.test.tsx +++ b/src/__tests__/SplitClient.test.tsx @@ -13,7 +13,7 @@ import { sdkBrowser } from './testUtils/sdkConfigs'; import { ISplitClientChildProps, ISplitFactoryChildProps } from '../types'; import { SplitFactoryProvider } from '../SplitFactoryProvider'; import { SplitClient } from '../SplitClient'; -import { SplitContext } from '../SplitContext'; +import { SplitContext, useSplitContext } from '../SplitContext'; import { INITIAL_STATUS, testAttributesBinding, TestComponentProps } from './testUtils/utils'; import { getStatus } from '../utils'; import { EXCEPTION_NO_SFP } from '../constants'; @@ -360,6 +360,31 @@ describe('SplitClient', () => { testAttributesBinding(Component); }); + + test('must overwrite `updateOn` options in context', () => { + render( + + {React.createElement(() => { + expect(useSplitContext()).toEqual({ + ...INITIAL_STATUS, + updateOnSdkReadyFromCache: false + }); + return null; + })} + + {React.createElement(() => { + expect(useSplitContext()).toEqual({ + ...INITIAL_STATUS, + updateOnSdkReady: false, + updateOnSdkReadyFromCache: false, + updateOnSdkTimedout: false + }); + return null; + })} + + + ); + }); }); // Tests to validate the migration from `SplitFactoryProvider` with child as a function in v1, to `SplitFactoryProvider` + `SplitClient` with child as a function in v2. diff --git a/src/__tests__/testUtils/utils.tsx b/src/__tests__/testUtils/utils.tsx index 027655e..7571873 100644 --- a/src/__tests__/testUtils/utils.tsx +++ b/src/__tests__/testUtils/utils.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { render } from '@testing-library/react'; -import { ISplitStatus } from '../../types'; +import { ISplitStatus, IUpdateProps } from '../../types'; const { SplitFactory: originalSplitFactory } = jest.requireActual('@splitsoftware/splitio/client'); export interface TestComponentProps { @@ -116,11 +116,15 @@ export function testAttributesBinding(Component: React.FunctionComponent); } -export const INITIAL_STATUS: ISplitStatus = { +export const INITIAL_STATUS: ISplitStatus & IUpdateProps = { isReady: false, isReadyFromCache: false, isTimedout: false, hasTimedout: false, lastUpdate: 0, isDestroyed: false, + updateOnSdkReady: true, + updateOnSdkReadyFromCache: true, + updateOnSdkTimedout: true, + updateOnSdkUpdate: true, } diff --git a/src/__tests__/useSplitClient.test.tsx b/src/__tests__/useSplitClient.test.tsx index c5ea38f..ea56ad9 100644 --- a/src/__tests__/useSplitClient.test.tsx +++ b/src/__tests__/useSplitClient.test.tsx @@ -244,7 +244,7 @@ describe('useSplitClient', () => { act(() => mainClient.__emitter__.emit(Event.SDK_READY_TIMED_OUT)); // do not trigger re-render because updateOnSdkTimedout is false expect(rendersCount).toBe(1); - expect(currentStatus).toMatchObject(INITIAL_STATUS); + expect(currentStatus).toMatchObject({ ...INITIAL_STATUS, updateOnSdkUpdate: false, updateOnSdkTimedout: false }); wrapper.rerender(); expect(rendersCount).toBe(2); @@ -263,7 +263,7 @@ describe('useSplitClient', () => { wrapper.rerender(); // should not update the status (SDK_UPDATE event should be ignored) expect(rendersCount).toBe(6); - expect(currentStatus).toEqual(previousStatus); + expect(currentStatus).toEqual({ ...previousStatus, updateOnSdkTimedout: false }); wrapper.rerender(); // trigger re-render and update the status because updateOnSdkUpdate is true and there was an SDK_UPDATE event expect(rendersCount).toBe(8); // @TODO optimize `useSplitClient` to avoid double render @@ -275,10 +275,31 @@ describe('useSplitClient', () => { wrapper.rerender(); expect(rendersCount).toBe(10); - expect(currentStatus).toEqual(previousStatus); + expect(currentStatus).toEqual({ ...previousStatus, updateOnSdkUpdate: false }); act(() => mainClient.__emitter__.emit(Event.SDK_UPDATE)); // do not trigger re-render because updateOnSdkUpdate is false now expect(rendersCount).toBe(10); }); + test('must prioritize explicitly provided `updateOn` options over context defaults', () => { + render( + + {React.createElement(() => { + expect(useSplitClient()).toEqual({ + ...INITIAL_STATUS, + updateOnSdkReadyFromCache: false + }); + + expect(useSplitClient({ updateOnSdkReady: false, updateOnSdkReadyFromCache: undefined, updateOnSdkTimedout: false })).toEqual({ + ...INITIAL_STATUS, + updateOnSdkReady: false, + updateOnSdkReadyFromCache: false, + updateOnSdkTimedout: false + }); + return null; + })} + + ); + }); + }); diff --git a/src/__tests__/useSplitManager.test.tsx b/src/__tests__/useSplitManager.test.tsx index a17d19c..9707042 100644 --- a/src/__tests__/useSplitManager.test.tsx +++ b/src/__tests__/useSplitManager.test.tsx @@ -32,15 +32,16 @@ describe('useSplitManager', () => { ); expect(hookResult).toStrictEqual({ + ...INITIAL_STATUS, manager: outerFactory.manager(), client: outerFactory.client(), factory: outerFactory, - ...INITIAL_STATUS, }); act(() => (outerFactory.client() as any).__emitter__.emit(Event.SDK_READY)); expect(hookResult).toStrictEqual({ + ...INITIAL_STATUS, manager: outerFactory.manager(), client: outerFactory.client(), factory: outerFactory, @@ -80,16 +81,17 @@ describe('useSplitManager', () => { ); expect(hookResult).toStrictEqual({ + ...INITIAL_STATUS, manager: outerFactory.manager(), client: outerFactory.client(), factory: outerFactory, - ...INITIAL_STATUS, }); act(() => (outerFactory.client() as any).__emitter__.emit(Event.SDK_READY)); // act(() => (outerFactory.client() as any).__emitter__.emit(Event.SDK_READY)); expect(hookResult).toStrictEqual({ + ...INITIAL_STATUS, manager: outerFactory.manager(), client: outerFactory.client(), factory: outerFactory, diff --git a/src/__tests__/withSplitTreatments.test.tsx b/src/__tests__/withSplitTreatments.test.tsx index f11f3a1..af178f2 100644 --- a/src/__tests__/withSplitTreatments.test.tsx +++ b/src/__tests__/withSplitTreatments.test.tsx @@ -8,6 +8,7 @@ jest.mock('@splitsoftware/splitio/client', () => { }); import { SplitFactory } from '@splitsoftware/splitio/client'; import { sdkBrowser } from './testUtils/sdkConfigs'; +import { INITIAL_STATUS } from './testUtils/utils'; /** Test target */ import { withSplitFactory } from '../withSplitFactory'; @@ -32,15 +33,10 @@ describe('withSplitTreatments', () => { expect((clientMock.getTreatmentsWithConfig as jest.Mock).mock.calls.length).toBe(0); expect(props).toStrictEqual({ + ...INITIAL_STATUS, factory: factory, client: clientMock, outerProp1: 'outerProp1', outerProp2: 2, treatments: getControlTreatmentsWithConfig(featureFlagNames), - isReady: false, - isReadyFromCache: false, - hasTimedout: false, - isTimedout: false, - isDestroyed: false, - lastUpdate: 0 }); return null; diff --git a/src/useSplitClient.ts b/src/useSplitClient.ts index 3b3e217..7d78b91 100644 --- a/src/useSplitClient.ts +++ b/src/useSplitClient.ts @@ -19,11 +19,13 @@ import { ISplitContextValues, IUseSplitClientOptions } from './types'; export function useSplitClient(options: IUseSplitClientOptions = {}): ISplitContextValues { const context = useSplitContext(); const { client: contextClient, factory } = context; - const { splitKey, attributes } = options; - const updateOnSdkReady = options.updateOnSdkReady ?? context.updateOnSdkReady; - const updateOnSdkReadyFromCache = options.updateOnSdkReadyFromCache ?? context.updateOnSdkReadyFromCache; - const updateOnSdkTimedout = options.updateOnSdkTimedout ?? context.updateOnSdkTimedout; - const updateOnSdkUpdate = options.updateOnSdkUpdate ?? context.updateOnSdkUpdate; + const { + splitKey, attributes, + updateOnSdkReady = context.updateOnSdkReady, + updateOnSdkReadyFromCache = context.updateOnSdkReadyFromCache, + updateOnSdkTimedout = context.updateOnSdkTimedout, + updateOnSdkUpdate = context.updateOnSdkUpdate + } = options; // @TODO Move `getSplitClient` side effects and reduce the function cognitive complexity // @TODO Once `SplitClient` is removed, which updates the context, simplify next line as `const client = factory ? getSplitClient(factory, splitKey) : undefined;` @@ -77,6 +79,6 @@ export function useSplitClient(options: IUseSplitClientOptions = {}): ISplitCont }, [client, updateOnSdkReady, updateOnSdkReadyFromCache, updateOnSdkTimedout, updateOnSdkUpdate, status]); return { - factory, client, ...status + factory, client, ...status, updateOnSdkReady, updateOnSdkReadyFromCache, updateOnSdkTimedout, updateOnSdkUpdate }; } From cc1a62229af11ef53f16b6a5c980ec260b24d43c Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 14 Apr 2025 00:54:04 -0300 Subject: [PATCH 5/7] rc --- .github/workflows/ci-cd.yml | 4 ++-- CHANGES.txt | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 8a4397b..cd4da2c 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -77,7 +77,7 @@ jobs: -Dsonar.pullrequest.base=${{ github.event.pull_request.base.ref }} - name: Store assets - if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development') + if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/default_options') uses: actions/upload-artifact@v4 with: name: assets @@ -88,7 +88,7 @@ jobs: name: Upload assets runs-on: ubuntu-latest needs: build - if: github.event_name == 'push' && github.ref == 'refs/heads/development' + if: github.event_name == 'push' && github.ref == 'refs/heads/default_options' strategy: matrix: environment: diff --git a/CHANGES.txt b/CHANGES.txt index babefc0..de08e24 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,4 @@ -2.2.0 (April XX, 2025) +2.2.0 (April 15, 2025) - Added `updateOnSdkUpdate`, `updateOnSdkReady`, `updateOnSdkReadyFromCache` and `updateOnSdkTimedout` props to the `SplitFactoryProvider` component to overwrite the default value (`true`) of the `updateOnSdk` options in the `useSplitClient` and `useSplitTreatments` hooks. - Updated development dependencies to use React v19 and TypeScript v4.5.5 to test compatibility and avoid type conflicts when using the SDK with React v19 types. diff --git a/package-lock.json b/package-lock.json index 2caa447..781c302 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.1", + "version": "2.1.2-rc.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio-react", - "version": "2.1.1", + "version": "2.1.2-rc.0", "license": "Apache-2.0", "dependencies": { "@splitsoftware/splitio": "11.2.0", diff --git a/package.json b/package.json index f0f5cbf..b5fcb80 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.1", + "version": "2.1.2-rc.0", "description": "A React library to easily integrate and use Split JS SDK", "main": "cjs/index.js", "module": "esm/index.js", From b16ee838c875ff519bd05d16f213339e9a00626d Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 14 Apr 2025 13:28:27 -0300 Subject: [PATCH 6/7] Remove redundant code and clarify type comments --- .github/workflows/ci-cd.yml | 4 ++-- src/SplitClient.tsx | 8 +------- src/types.ts | 14 +++++--------- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index cd4da2c..8a4397b 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -77,7 +77,7 @@ jobs: -Dsonar.pullrequest.base=${{ github.event.pull_request.base.ref }} - name: Store assets - if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/default_options') + if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development') uses: actions/upload-artifact@v4 with: name: assets @@ -88,7 +88,7 @@ jobs: name: Upload assets runs-on: ubuntu-latest needs: build - if: github.event_name == 'push' && github.ref == 'refs/heads/default_options' + if: github.event_name == 'push' && github.ref == 'refs/heads/development' strategy: matrix: environment: diff --git a/src/SplitClient.tsx b/src/SplitClient.tsx index 4715d67..fd146ae 100644 --- a/src/SplitClient.tsx +++ b/src/SplitClient.tsx @@ -17,13 +17,7 @@ export function SplitClient(props: ISplitClientProps) { const context = useSplitClient(props); return ( - + { typeof children === 'function' ? children(context) : diff --git a/src/types.ts b/src/types.ts index ef5ead3..96836c8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -34,7 +34,7 @@ export interface ISplitStatus { isDestroyed: boolean; /** - * `lastUpdate` indicates when the most recent status event was emitted. This timestamp is only updated for events that are being listened to, + * `lastUpdate` indicates the timestamp of the most recent status event. This timestamp is only updated for events that are being listened to, * configured via the `updateOnSdkReady` option for `SDK_READY` event, `updateOnSdkReadyFromCache` for `SDK_READY_FROM_CACHE` event, * `updateOnSdkTimedout` for `SDK_READY_TIMED_OUT` event, and `updateOnSdkUpdate` for `SDK_UPDATE` event. */ @@ -47,29 +47,25 @@ export interface ISplitStatus { export interface IUpdateProps { /** - * `updateOnSdkUpdate` indicates if the hook or component will update (i.e., re-render) in case of an `SDK_UPDATE` event. - * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_UPDATE`. + * `updateOnSdkUpdate` indicates if the hook or component will update (i.e., re-render) or not in case of an `SDK_UPDATE` event. * It's value is `true` by default. */ updateOnSdkUpdate?: boolean; /** - * `updateOnSdkTimedout` indicates if the hook or component will update (i.e., re-render) in case of a `SDK_READY_TIMED_OUT` event. - * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_READY_TIMED_OUT`. + * `updateOnSdkTimedout` indicates if the hook or component will update (i.e., re-render) or not in case of a `SDK_READY_TIMED_OUT` event. * It's value is `true` by default. */ updateOnSdkTimedout?: boolean; /** - * `updateOnSdkReady` indicates if the hook or component will update (i.e., re-render) in case of a `SDK_READY` event. - * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_READY`. + * `updateOnSdkReady` indicates if the hook or component will update (i.e., re-render) or not in case of a `SDK_READY` event. * It's value is `true` by default. */ updateOnSdkReady?: boolean; /** - * `updateOnSdkReadyFromCache` indicates if the hook or component will update (i.e., re-render) in case of a `SDK_READY_FROM_CACHE` event. - * If `true`, hooks or components consuming the context (such as `useSplitClient` and `useSplitTreatments`) will re-render on `SDK_READY_FROM_CACHE`. + * `updateOnSdkReadyFromCache` indicates if the hook or component will update (i.e., re-render) or not in case of a `SDK_READY_FROM_CACHE` event. * This params is only relevant when using `'LOCALSTORAGE'` as storage type, since otherwise the event is never emitted. * It's value is `true` by default. */ From c5def426d1e87f4bb20ab785a7e9f126130f6922 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 15 Apr 2025 15:51:07 -0300 Subject: [PATCH 7/7] Stable version --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 781c302..8f93d05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.2-rc.0", + "version": "2.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio-react", - "version": "2.1.2-rc.0", + "version": "2.2.0", "license": "Apache-2.0", "dependencies": { "@splitsoftware/splitio": "11.2.0", diff --git a/package.json b/package.json index b5fcb80..2282f56 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.2-rc.0", + "version": "2.2.0", "description": "A React library to easily integrate and use Split JS SDK", "main": "cjs/index.js", "module": "esm/index.js",