From d251908bf3883b4b8c6c1bc31332e34217250f08 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 7 Apr 2025 16:28:34 -0300 Subject: [PATCH 01/11] Update README, GH action version, and fix typo --- .github/workflows/ci-cd.yml | 2 +- README.md | 3 ++- src/types.ts | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 467d201..8a4397b 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -28,7 +28,7 @@ jobs: fetch-depth: 0 - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 'lts/*' cache: 'npm' diff --git a/README.md b/README.md index 8c11056..6566361 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ Split has built and maintains SDKs for: * .NET [Github](https://github.com/splitio/dotnet-client) [Docs](https://help.split.io/hc/en-us/articles/360020240172--NET-SDK) * Android [Github](https://github.com/splitio/android-client) [Docs](https://help.split.io/hc/en-us/articles/360020343291-Android-SDK) * Angular [Github](https://github.com/splitio/angular-sdk-plugin) [Docs](https://help.split.io/hc/en-us/articles/6495326064397-Angular-utilities) +* Elixir thin-client [Github](https://github.com/splitio/elixir-thin-client) [Docs](https://help.split.io/hc/en-us/articles/26988707417869-Elixir-Thin-Client-SDK) * Flutter [Github](https://github.com/splitio/flutter-sdk-plugin) [Docs](https://help.split.io/hc/en-us/articles/8096158017165-Flutter-plugin) * GO [Github](https://github.com/splitio/go-client) [Docs](https://help.split.io/hc/en-us/articles/360020093652-Go-SDK) * iOS [Github](https://github.com/splitio/ios-client) [Docs](https://help.split.io/hc/en-us/articles/360020401491-iOS-SDK) @@ -96,4 +97,4 @@ For a comprehensive list of open source projects visit our [Github page](https:/ **Learn more about Split:** -Visit [split.io/product](https://www.split.io/product) for an overview of Split, or visit our documentation at [help.split.io](http://help.split.io) for more detailed information. +Visit [split.io/product](https://www.split.io/product) for an overview of Split, or visit our documentation at [help.split.io](https://help.split.io) for more detailed information. diff --git a/src/types.ts b/src/types.ts index f4eb999..6fb4f8a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -18,7 +18,7 @@ export interface ISplitStatus { /** * `isTimedout` indicates if the Split SDK client has triggered an `SDK_READY_TIMED_OUT` event and is not ready to be consumed. - * In other words, `isTimedout` is equivalent to `hasTimeout && !isReady`. + * In other words, `isTimedout` is equivalent to `hasTimedout && !isReady`. */ isTimedout: boolean; From 117344273c37dd2286d151a64e16ea86ec529efc Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Mon, 7 Apr 2025 23:42:46 -0300 Subject: [PATCH 02/11] Fix useSplitClient hook and validate with test --- src/__tests__/useSplitClient.test.tsx | 38 +++++++++++++++++++++++---- src/useSplitClient.ts | 6 +++-- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/__tests__/useSplitClient.test.tsx b/src/__tests__/useSplitClient.test.tsx index 96eee88..6b39c9c 100644 --- a/src/__tests__/useSplitClient.test.tsx +++ b/src/__tests__/useSplitClient.test.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { act, render } from '@testing-library/react'; +import { act, fireEvent, render } from '@testing-library/react'; /** Mocks */ import { mockSdk, Event } from './testUtils/mockSplitFactory'; @@ -87,8 +87,9 @@ describe('useSplitClient', () => { let countSplitContext = 0, countUseSplitClient = 0, countUseSplitClientUser2 = 0; let countUseSplitClientWithoutUpdate = 0, countUseSplitClientUser2WithoutTimeout = 0; + let previousLastUpdate = -1; - render( + const { getByTestId } = render( <> @@ -129,9 +130,35 @@ describe('useSplitClient', () => { return null; })} {React.createElement(() => { - useSplitClient({ splitKey: sdkBrowser.core.key, updateOnSdkUpdate: false }).client; + const [state, setState] = React.useState(false); + + const { isReady, isReadyFromCache, hasTimedout, lastUpdate } = useSplitClient({ splitKey: sdkBrowser.core.key, updateOnSdkUpdate: false }); countUseSplitClientWithoutUpdate++; - return null; + switch (countUseSplitClientWithoutUpdate) { + case 1: // initial render + expect([isReady, isReadyFromCache, hasTimedout]).toEqual([false, false, false]); + expect(lastUpdate).toBe(0); + break; + case 2: // SDK_READY_FROM_CACHE + expect([isReady, isReadyFromCache, hasTimedout]).toEqual([false, true, false]); + expect(lastUpdate).toBeGreaterThan(previousLastUpdate); + break; + case 3: // SDK_READY + expect([isReady, isReadyFromCache, hasTimedout]).toEqual([true, true, false]); + expect(lastUpdate).toBeGreaterThan(previousLastUpdate); + break; + case 4: // Forced update + expect([isReady, isReadyFromCache, hasTimedout]).toEqual([true, true, false]); + expect(lastUpdate).toBe(previousLastUpdate); + break; + default: + throw new Error('Unexpected render'); + } + + previousLastUpdate = lastUpdate; + return ( + + ); })} {React.createElement(() => { useSplitClient({ splitKey: 'user_2', updateOnSdkTimedout: false }); @@ -149,6 +176,7 @@ describe('useSplitClient', () => { act(() => user2Client.__emitter__.emit(Event.SDK_READY)); act(() => mainClient.__emitter__.emit(Event.SDK_UPDATE)); act(() => user2Client.__emitter__.emit(Event.SDK_UPDATE)); + act(() => fireEvent.click(getByTestId('update-button'))); // SplitFactoryProvider renders once expect(countSplitContext).toEqual(1); @@ -160,7 +188,7 @@ describe('useSplitClient', () => { expect(countUseSplitClientUser2).toEqual(5); // If useSplitClient retrieves the main client and have updateOnSdkUpdate = false, it doesn't render when the main client updates. - expect(countUseSplitClientWithoutUpdate).toEqual(3); + expect(countUseSplitClientWithoutUpdate).toEqual(4); // If useSplitClient retrieves a different client and have updateOnSdkTimedout = false, it doesn't render when the the new client times out. expect(countUseSplitClientUser2WithoutTimeout).toEqual(4); diff --git a/src/useSplitClient.ts b/src/useSplitClient.ts index fa8983b..f11ec75 100644 --- a/src/useSplitClient.ts +++ b/src/useSplitClient.ts @@ -37,8 +37,10 @@ export function useSplitClient(options?: IUseSplitClientOptions): ISplitContextV initAttributes(client, attributes); - const status = getStatus(client); - const [, setLastUpdate] = React.useState(status.lastUpdate); + const [lastUpdate, setLastUpdate] = React.useState(0); + // `getStatus` is not pure. Its result depends on `client` and `lastUpdate` + // eslint-disable-next-line react-hooks/exhaustive-deps + const status = React.useMemo(() => getStatus(client), [client, lastUpdate]); // Handle client events React.useEffect(() => { From 99574bb85e27aed2415d41b464d8d83b977f7561 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 8 Apr 2025 01:08:23 -0300 Subject: [PATCH 03/11] Update tests --- src/__tests__/SplitTreatments.test.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/__tests__/SplitTreatments.test.tsx b/src/__tests__/SplitTreatments.test.tsx index ef61ad0..6673db5 100644 --- a/src/__tests__/SplitTreatments.test.tsx +++ b/src/__tests__/SplitTreatments.test.tsx @@ -228,7 +228,7 @@ describe.each([ }) { return ( - + @@ -269,7 +269,7 @@ describe.each([ }); it('rerenders and re-evaluates feature flags if names are not equals (shallow array comparison).', () => { - wrapper.rerender(); + wrapper.rerender(); expect(renderTimes).toBe(2); expect(outerFactory.client().getTreatmentsWithConfig).toBeCalledTimes(2); @@ -290,14 +290,14 @@ describe.each([ it('rerenders and re-evaluates feature flags if attributes are not equals (shallow object comparison).', () => { const attributesRef = { ...attributes, att2: 'att2' }; - wrapper.rerender(); + wrapper.rerender(); expect(renderTimes).toBe(2); expect(outerFactory.client().getTreatmentsWithConfig).toBeCalledTimes(2); // If passing same reference but mutated (bad practice), the component re-renders but doesn't re-evaluate feature flags attributesRef.att2 = 'att2_val2'; - wrapper.rerender(); + wrapper.rerender(); expect(renderTimes).toBe(3); expect(outerFactory.client().getTreatmentsWithConfig).toBeCalledTimes(2); }); @@ -307,10 +307,11 @@ describe.each([ // State update and split evaluation act(() => (outerFactory as any).client().__emitter__.emit(Event.SDK_UPDATE)); + expect(outerFactory.client().getTreatmentsWithConfig).toBeCalledTimes(2); // State update after destroy doesn't re-evaluate because the sdk is not operational (outerFactory as any).client().destroy(); - wrapper.rerender(); + wrapper.rerender(); // Updates were batched as a single render, due to automatic batching https://reactjs.org/blog/2022/03/29/react-v18.html#new-feature-automatic-batching expect(renderTimes).toBe(3); From bdb5ee3df0c95c391f89de9570be43eb327ad7f4 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 8 Apr 2025 01:10:16 -0300 Subject: [PATCH 04/11] Add tests --- src/__tests__/SplitTreatments.test.tsx | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/__tests__/SplitTreatments.test.tsx b/src/__tests__/SplitTreatments.test.tsx index 6673db5..4ff0a78 100644 --- a/src/__tests__/SplitTreatments.test.tsx +++ b/src/__tests__/SplitTreatments.test.tsx @@ -200,18 +200,18 @@ let renderTimes = 0; * Tests for asserting that client.getTreatmentsWithConfig and client.getTreatmentsWithConfigByFlagSets are not called unnecessarily when using SplitTreatments and useSplitTreatments. */ describe.each([ - ({ names, flagSets, attributes }: { names?: string[], flagSets?: string[], attributes?: SplitIO.Attributes }) => ( + ({ names, flagSets, attributes, updateOnSdkUpdate }: { names?: string[], flagSets?: string[], attributes?: SplitIO.Attributes, updateOnSdkUpdate?: boolean }) => ( // @ts-expect-error names and flagSets are mutually exclusive - + {() => { renderTimes++; return null; }} ), - ({ names, flagSets, attributes }: { names?: string[], flagSets?: string[], attributes?: SplitIO.Attributes }) => { + ({ names, flagSets, attributes, updateOnSdkUpdate }: { names?: string[], flagSets?: string[], attributes?: SplitIO.Attributes, updateOnSdkUpdate?: boolean }) => { // @ts-expect-error names and flagSets are mutually exclusive - useSplitTreatments({ names, flagSets, attributes }); + useSplitTreatments({ names, flagSets, attributes, updateOnSdkUpdate }); renderTimes++; return null; } @@ -219,17 +219,18 @@ describe.each([ let outerFactory = SplitFactory(sdkBrowser); (outerFactory as any).client().__emitter__.emit(Event.SDK_READY); - function Component({ names, flagSets, attributes, splitKey, clientAttributes }: { + function Component({ names, flagSets, attributes, splitKey, clientAttributes, updateOnSdkUpdate }: { names?: ISplitTreatmentsProps['names'] flagSets?: ISplitTreatmentsProps['flagSets'] attributes: ISplitTreatmentsProps['attributes'] splitKey: ISplitClientProps['splitKey'] - clientAttributes?: ISplitClientProps['attributes'] + clientAttributes?: ISplitClientProps['attributes'], + updateOnSdkUpdate?: boolean }) { return ( - + ); @@ -322,6 +323,17 @@ describe.each([ (outerFactory as any).client().__emitter__.emit(Event.SDK_READY); }); + it('rerenders and does not re-evaluate feature flags if lastUpdate timestamp does not change (e.g., SDK_UPDATE event but `updateOnSdkUpdate` false).', () => { + wrapper.rerender(); + expect(renderTimes).toBe(2); + expect(outerFactory.client().getTreatmentsWithConfig).toBeCalledTimes(1); + + // SDK_UPDATE doesn't re-evaluate due to updateOnSdkUpdate false + act(() => (outerFactory as any).client().__emitter__.emit(Event.SDK_UPDATE)); + expect(renderTimes).toBe(3); + expect(outerFactory.client().getTreatmentsWithConfig).toBeCalledTimes(1); + }); + it('rerenders and re-evaluates feature flags if client changes.', async () => { wrapper.rerender(); await act(() => (outerFactory as any).client('otherKey').__emitter__.emit(Event.SDK_READY)); From 815145c6abc7a31acac3935ddeb3f8d846a81290 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 8 Apr 2025 11:14:28 -0300 Subject: [PATCH 05/11] Update changelog entry and prepare rc --- CHANGES.txt | 3 +++ package-lock.json | 4 ++-- package.json | 2 +- src/__tests__/useSplitClient.test.tsx | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index a17ad4f..ca5ea68 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,6 @@ +2.1.1 (April 8, 2025) + - Bugfix - Fixed `useSplitClient` and `useSplitTreatments` hooks to properly respect `updateOn` options. Previously, if the hooks were re-called due to a component re-render, it used the latest version of the SDK client status ignoring when `updateOn` options were set to `false`. + 2.1.0 (March 28, 2025) - Added a new optional `properties` argument to the options object of the `useSplitTreatments` hook, allowing to pass a map of properties to append to the generated impressions sent to Split backend. Read more in our docs. - Updated @splitsoftware/splitio package to version 11.2.0 that includes some minor updates: diff --git a/package-lock.json b/package-lock.json index 26cca49..8e6252c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.0", + "version": "2.1.1-rc.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio-react", - "version": "2.1.0", + "version": "2.1.1-rc.0", "license": "Apache-2.0", "dependencies": { "@splitsoftware/splitio": "11.2.0", diff --git a/package.json b/package.json index 30c702d..ecf2b93 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.0", + "version": "2.1.1-rc.0", "description": "A React library to easily integrate and use Split JS SDK", "main": "cjs/index.js", "module": "esm/index.js", diff --git a/src/__tests__/useSplitClient.test.tsx b/src/__tests__/useSplitClient.test.tsx index 6b39c9c..cd6a1e9 100644 --- a/src/__tests__/useSplitClient.test.tsx +++ b/src/__tests__/useSplitClient.test.tsx @@ -147,7 +147,7 @@ describe('useSplitClient', () => { expect([isReady, isReadyFromCache, hasTimedout]).toEqual([true, true, false]); expect(lastUpdate).toBeGreaterThan(previousLastUpdate); break; - case 4: // Forced update + case 4: // Forced re-render, lastUpdate doesn't change after SDK_UPDATE due to updateOnSdkUpdate = false expect([isReady, isReadyFromCache, hasTimedout]).toEqual([true, true, false]); expect(lastUpdate).toBe(previousLastUpdate); break; From 35ba9f9f4c9157bda0c76ba3e2abf2b3dce5709a Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 8 Apr 2025 11:33:59 -0300 Subject: [PATCH 06/11] Stable version --- CHANGES.txt | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index ca5ea68..f4d5676 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,5 @@ 2.1.1 (April 8, 2025) - - Bugfix - Fixed `useSplitClient` and `useSplitTreatments` hooks to properly respect `updateOn` options. Previously, if the hooks were re-called due to a component re-render, it used the latest version of the SDK client status ignoring when `updateOn` options were set to `false`. + - Bugfix - Fixed `useSplitClient` and `useSplitTreatments` hooks to properly respect `updateOn` options. Previously, if the hooks were re-called due to a component re-render, they used the latest version of the SDK client status ignoring when `updateOn` options were set to `false`. 2.1.0 (March 28, 2025) - Added a new optional `properties` argument to the options object of the `useSplitTreatments` hook, allowing to pass a map of properties to append to the generated impressions sent to Split backend. Read more in our docs. diff --git a/package-lock.json b/package-lock.json index 8e6252c..baab405 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.1-rc.0", + "version": "2.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio-react", - "version": "2.1.1-rc.0", + "version": "2.1.1", "license": "Apache-2.0", "dependencies": { "@splitsoftware/splitio": "11.2.0", diff --git a/package.json b/package.json index ecf2b93..936cb8e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.1-rc.0", + "version": "2.1.1", "description": "A React library to easily integrate and use Split JS SDK", "main": "cjs/index.js", "module": "esm/index.js", From 4803370138bc0a57fcc0da0d6dadd21056c4e38b Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 8 Apr 2025 11:40:10 -0300 Subject: [PATCH 07/11] Clarify changelog entry --- CHANGES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index f4d5676..2c68b75 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,5 @@ 2.1.1 (April 8, 2025) - - Bugfix - Fixed `useSplitClient` and `useSplitTreatments` hooks to properly respect `updateOn` options. Previously, if the hooks were re-called due to a component re-render, they used the latest version of the SDK client status ignoring when `updateOn` options were set to `false`. + - Bugfix - Fixed `useSplitClient` and `useSplitTreatments` hooks to properly respect `updateOn` options. Previously, if the hooks were re-called due to a component re-render, they used the latest version of the SDK client status ignoring when `updateOn` options were set to `false` and resulting in unexpected changes in treatment values. 2.1.0 (March 28, 2025) - Added a new optional `properties` argument to the options object of the `useSplitTreatments` hook, allowing to pass a map of properties to append to the generated impressions sent to Split backend. Read more in our docs. From 3b45ba9f7cf333ef7c98990a8738d8bc83bd4703 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 8 Apr 2025 15:05:17 -0300 Subject: [PATCH 08/11] Fix with double re-render --- src/__tests__/useSplitClient.test.tsx | 44 ++++++++++++++++++++------- src/useSplitClient.ts | 5 ++- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/__tests__/useSplitClient.test.tsx b/src/__tests__/useSplitClient.test.tsx index cd6a1e9..dff3031 100644 --- a/src/__tests__/useSplitClient.test.tsx +++ b/src/__tests__/useSplitClient.test.tsx @@ -13,7 +13,7 @@ import { sdkBrowser } from './testUtils/sdkConfigs'; import { useSplitClient } from '../useSplitClient'; import { SplitFactoryProvider } from '../SplitFactoryProvider'; import { SplitContext } from '../SplitContext'; -import { testAttributesBinding, TestComponentProps } from './testUtils/utils'; +import { INITIAL_STATUS, testAttributesBinding, TestComponentProps } from './testUtils/utils'; import { EXCEPTION_NO_SFP } from '../constants'; describe('useSplitClient', () => { @@ -222,9 +222,11 @@ describe('useSplitClient', () => { const mainClient = outerFactory.client() as any; let rendersCount = 0; + let currentStatus, previousStatus; function InnerComponent(updateOptions) { - useSplitClient(updateOptions); + previousStatus = currentStatus; + currentStatus = useSplitClient(updateOptions); rendersCount++; return null; } @@ -237,26 +239,46 @@ describe('useSplitClient', () => { ) } - const wrapper = render(); + const wrapper = render(); expect(rendersCount).toBe(1); - act(() => mainClient.__emitter__.emit(Event.SDK_READY)); // trigger re-render + 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); + + wrapper.rerender(); expect(rendersCount).toBe(2); + expect(currentStatus).toEqual(previousStatus); + + wrapper.rerender(); // trigger re-render because there was an SDK_READY_TIMED_OUT event + expect(rendersCount).toBe(4); + expect(currentStatus).toMatchObject({ isReady: false, isReadyFromCache: false, hasTimedout: true }); + + act(() => mainClient.__emitter__.emit(Event.SDK_READY)); // trigger re-render + expect(rendersCount).toBe(5); + expect(currentStatus).toMatchObject({ isReady: true, isReadyFromCache: false, hasTimedout: true }); act(() => mainClient.__emitter__.emit(Event.SDK_UPDATE)); // do not trigger re-render because updateOnSdkUpdate is false - expect(rendersCount).toBe(2); + expect(rendersCount).toBe(5); + + wrapper.rerender(); // trigger re-render but should not update the status (SDK_UPDATE event should be ignored) + expect(rendersCount).toBe(6); + expect(currentStatus).toEqual(previousStatus); - wrapper.rerender(); // trigger re-render - expect(rendersCount).toBe(3); + wrapper.rerender(); // trigger re-render because there was an SDK_UPDATE event + expect(rendersCount).toBe(8); + expect(currentStatus.lastUpdate).toBeGreaterThan(previousStatus.lastUpdate); act(() => mainClient.__emitter__.emit(Event.SDK_UPDATE)); // trigger re-render because updateOnSdkUpdate is true now - expect(rendersCount).toBe(4); + expect(rendersCount).toBe(9); + expect(currentStatus.lastUpdate).toBeGreaterThan(previousStatus.lastUpdate); - wrapper.rerender(); // trigger re-render - expect(rendersCount).toBe(5); + wrapper.rerender(); + expect(rendersCount).toBe(10); + expect(currentStatus).toEqual(previousStatus); act(() => mainClient.__emitter__.emit(Event.SDK_UPDATE)); // do not trigger re-render because updateOnSdkUpdate is false now - expect(rendersCount).toBe(5); + expect(rendersCount).toBe(10); }); }); diff --git a/src/useSplitClient.ts b/src/useSplitClient.ts index f11ec75..29269dd 100644 --- a/src/useSplitClient.ts +++ b/src/useSplitClient.ts @@ -68,7 +68,10 @@ export function useSplitClient(options?: IUseSplitClientOptions): ISplitContextV if (!status.hasTimedout) update(); } } - if (updateOnSdkUpdate !== false) client.on(client.Event.SDK_UPDATE, update); + if (updateOnSdkUpdate !== false) { + client.on(client.Event.SDK_UPDATE, update); + if (statusOnEffect.isReady && statusOnEffect.lastUpdate > status.lastUpdate) update(); + } return () => { // Unsubscribe from events From eeb5fe8fee695cb9be910c9766f84739d314cdd3 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 8 Apr 2025 17:43:23 -0300 Subject: [PATCH 09/11] rc --- CHANGES.txt | 2 +- package-lock.json | 4 ++-- package.json | 2 +- src/__tests__/useSplitClient.test.tsx | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 2c68b75..fb80a8e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,5 @@ 2.1.1 (April 8, 2025) - - Bugfix - Fixed `useSplitClient` and `useSplitTreatments` hooks to properly respect `updateOn` options. Previously, if the hooks were re-called due to a component re-render, they used the latest version of the SDK client status ignoring when `updateOn` options were set to `false` and resulting in unexpected changes in treatment values. + - Bugfixing - Fixed `useSplitClient` and `useSplitTreatments` hooks to properly respect `updateOn` options. Previously, if the hooks were re-called due to a component re-render, they used the latest version of the SDK client status ignoring when `updateOn` options were set to `false` and resulting in unexpected changes in treatment values. 2.1.0 (March 28, 2025) - Added a new optional `properties` argument to the options object of the `useSplitTreatments` hook, allowing to pass a map of properties to append to the generated impressions sent to Split backend. Read more in our docs. diff --git a/package-lock.json b/package-lock.json index baab405..d27a4cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.1", + "version": "2.1.1-rc.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio-react", - "version": "2.1.1", + "version": "2.1.1-rc.1", "license": "Apache-2.0", "dependencies": { "@splitsoftware/splitio": "11.2.0", diff --git a/package.json b/package.json index 936cb8e..e65e277 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.1", + "version": "2.1.1-rc.1", "description": "A React library to easily integrate and use Split JS SDK", "main": "cjs/index.js", "module": "esm/index.js", diff --git a/src/__tests__/useSplitClient.test.tsx b/src/__tests__/useSplitClient.test.tsx index dff3031..e41e69f 100644 --- a/src/__tests__/useSplitClient.test.tsx +++ b/src/__tests__/useSplitClient.test.tsx @@ -261,15 +261,15 @@ describe('useSplitClient', () => { act(() => mainClient.__emitter__.emit(Event.SDK_UPDATE)); // do not trigger re-render because updateOnSdkUpdate is false expect(rendersCount).toBe(5); - wrapper.rerender(); // trigger re-render but should not update the status (SDK_UPDATE event should be ignored) + wrapper.rerender(); // should not update the status (SDK_UPDATE event should be ignored) expect(rendersCount).toBe(6); expect(currentStatus).toEqual(previousStatus); - wrapper.rerender(); // trigger re-render because there was an SDK_UPDATE event + wrapper.rerender(); // trigger re-render and update the status because updateOnSdkUpdate is true and there was an SDK_UPDATE event expect(rendersCount).toBe(8); expect(currentStatus.lastUpdate).toBeGreaterThan(previousStatus.lastUpdate); - act(() => mainClient.__emitter__.emit(Event.SDK_UPDATE)); // trigger re-render because updateOnSdkUpdate is true now + act(() => mainClient.__emitter__.emit(Event.SDK_UPDATE)); // trigger re-render because updateOnSdkUpdate is true expect(rendersCount).toBe(9); expect(currentStatus.lastUpdate).toBeGreaterThan(previousStatus.lastUpdate); From c7b8ab0ea8e97928ad8d7c777b9119095fb78ed4 Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 8 Apr 2025 18:08:30 -0300 Subject: [PATCH 10/11] 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 d27a4cf..baab405 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.1-rc.1", + "version": "2.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@splitsoftware/splitio-react", - "version": "2.1.1-rc.1", + "version": "2.1.1", "license": "Apache-2.0", "dependencies": { "@splitsoftware/splitio": "11.2.0", diff --git a/package.json b/package.json index e65e277..936cb8e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@splitsoftware/splitio-react", - "version": "2.1.1-rc.1", + "version": "2.1.1", "description": "A React library to easily integrate and use Split JS SDK", "main": "cjs/index.js", "module": "esm/index.js", From 02a26beea9484c29737b9482117f9eee2c93ca4d Mon Sep 17 00:00:00 2001 From: Emiliano Sanchez Date: Tue, 8 Apr 2025 18:16:26 -0300 Subject: [PATCH 11/11] Comment update --- src/useSplitClient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/useSplitClient.ts b/src/useSplitClient.ts index 29269dd..d9344af 100644 --- a/src/useSplitClient.ts +++ b/src/useSplitClient.ts @@ -31,7 +31,7 @@ export function useSplitClient(options?: IUseSplitClientOptions): ISplitContextV const context = useSplitContext(); const { client: contextClient, factory } = context; - // @TODO Move `getSplitClient` side effects + // @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;` const client = factory && splitKey ? getSplitClient(factory, splitKey) : contextClient;