Skip to content

Commit 93ac080

Browse files
Merge pull request #249 from splitio/FME-10595-add-evaluation-hooks
[FME-10595] Add `useTreatment*` hooks for evaluation
2 parents 3ced1c1 + 202939c commit 93ac080

26 files changed

+1121
-139
lines changed

CHANGES.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
2.6.0 (October 31, 2025)
1+
2.6.0 (November 4, 2025)
2+
- Added `useTreatment`, `useTreatments`, `useTreatmentWithConfig` and `useTreatmentsWithConfig` hooks to replace the now deprecated `useSplitTreatments` hook.
23
- Updated @splitsoftware/splitio package to version 11.8.0 that includes minor updates:
34
- Added new configuration for Fallback Treatments, which allows setting a treatment value and optional config to be returned in place of "control", either globally or by flag. Read more in our docs.
45
- Added support for custom loggers: added `logger` configuration option and `factory.Logger.setLogger` method to allow the SDK to use a custom logger.

MIGRATION-GUIDE.md

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,32 @@
33

44
React SDK v2.0.0 has a few breaking changes that you should consider when migrating from a previous version. The main changes are:
55

6-
### • Deprecated `useClient`, `useTreatments`, and `useManager` hooks have been removed.
76

8-
Follow [this section](#migrating-to-get-react-sdk-v1100-improvements-replacing-the-deprecated-useclient-usetreatments-and-usemanager-hooks) to migrate to the new hooks `useSplitClient`, `useSplitTreatments`, and `useSplitManager`.
7+
### `useTreatments` hook was removed in v2.0.0, but re-introduced in v2.6.0 with a different API:
8+
9+
Since v2.6.0, there are 4 hooks variants to evaluate feature flags, to better cover the different evaluation methods available in the JavaScript SDK client:
10+
11+
- `useTreatment`: returns a treatment value for a given feature flag name. It calls `client.getTreatment()` method under the hood.
12+
- `useTreatmentWithConfig`: returns a treatment value and its configuration for a given feature flag name. It calls `client.getTreatmentWithConfig()` method under the hood.
13+
- `useTreatments`: returns an object with treatment values for multiple feature flag names. It calls `client.getTreatments()` or `client.getTreatmentsByFlagSets()` methods under the hood, depending if the `names` or `flagSets` option is provided.
14+
- `useTreatmentsWithConfig`: returns an object with treatment values and their configurations for multiple feature flag names. It calls `client.getTreatmentsWithConfig()` or `client.getTreatmentsWithConfigByFlagSets()` methods under the hood, depending if the `names` or `flagSets` option is provided.
15+
16+
The `useTreatments` hook from v1.x.x should be replaced with `useTreatmentsWithConfig`, as follows:
17+
18+
```javascript
19+
// v1.x.x
20+
const treatments = useTreatments(featureFlagNames, optionalAttributes, optionalSplitKey);
21+
22+
// v2.6.0+
23+
const { treatments } = useTreatmentsWithConfig({ names: featureFlagNames, attributes: optionalAttributes, splitKey: optionalSplitKey });
24+
25+
// v2.0.0-v2.5.0
26+
const { treatments } = useSplitTreatments({ names: featureFlagNames, attributes: optionalAttributes, splitKey: optionalSplitKey });
27+
```
28+
29+
### • Deprecated `useClient` and `useManager` hooks have been removed.
30+
31+
Follow [this section](#migrating-to-get-react-sdk-v1100-improvements-replacing-the-deprecated-useclient-usetreatments-and-usemanager-hooks) to migrate to the new hooks `useSplitClient` and `useSplitManager`.
932

1033
### • Updated the default value of `updateOnSdkUpdate` and `updateOnSdkTimedout` options to `true`.
1134

@@ -15,7 +38,7 @@ Consider setting the `updateOnSdkUpdate` option to `false` to revert to the prev
1538

1639
The same applies for the equivalent props in the `[with]SplitClient` and `[with]SplitTreatments` components, although these components are deprecated and we recommend [migrating to their hook alternatives](#-high-order-components-withsplitclient-withsplittreatments-and-components-that-accept-a-render-function-as-child-component-splittreatments-and-splitclient-have-been-deprecated-and-might-be-removed-in-a-future-major-release).
1740

18-
### • Deprecated `SplitFactory` provider has been removed, `withSplitFactory` is deprecated, and `SplitFactoryProvider` doesn't accept `updateOn` props and a render function as children anymore.
41+
### • Deprecated `SplitFactory` provider has been removed, `withSplitFactory` is deprecated, and `SplitFactoryProvider` doesn't accept a render function as children anymore.
1942

2043
To migrate your existing code to the new version of `SplitFactoryProvider`, consider the following refactor example:
2144

@@ -53,21 +76,21 @@ should be refactored to:
5376

5477
```tsx
5578
const MyComponent = () => {
56-
const props: ISplitContextValues = useSplitClient({ updateOnSdkUpdate: false });
79+
const props: ISplitContextValues = useSplitClient();
5780
const { factory, client, isReady, isReadyFromCache, ... } = props;
5881
...
5982
};
6083

6184
const App = () => {
6285
return (
63-
<SplitFactoryProvider config={mySplitConfig} attributes={DEFAULT_CLIENT_ATTRIBUTES} >
86+
<SplitFactoryProvider config={mySplitConfig} updateOnSdkUpdate={false} attributes={DEFAULT_CLIENT_ATTRIBUTES} >
6487
<MyComponent />
6588
</SplitFactoryProvider>
6689
);
6790
};
6891
```
6992

70-
Notice that `MyComponent` was refactored to use the `useSplitClient` hook and is passed as a React JSX element rather than a render function. The `useSplitClient` hook is called without providing a `splitKey` param. This means that the default client (whose key is set in the `core.key` property of the `mySplitConfig` object) will be used, and the `updateOnSdkUpdate` and `attributes` props are passed as options to the hook.
93+
Notice that `MyComponent` was refactored to use the `useSplitClient` hook and is passed as a React JSX element rather than a render function. The `useSplitClient` hook is called without providing a `splitKey` param. This means that the default client (whose key is set in the `core.key` property of the `mySplitConfig` object) will be used.
7194

7295
### • High-Order-Components (`withSplitClient`, `withSplitTreatments`) and components that accept a render function as child component (`SplitTreatments`, and `SplitClient`) have been deprecated and might be removed in a future major release.
7396

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Below is a simple example that describes the instantiation and most basic usage
1818
import React from 'react';
1919

2020
// Import SDK functions
21-
import { SplitFactoryProvider, useSplitTreatments } from '@splitsoftware/splitio-react';
21+
import { SplitFactoryProvider, useTreatment } from '@splitsoftware/splitio-react';
2222

2323
// Define your config object
2424
const CONFIG = {
@@ -29,18 +29,18 @@ const CONFIG = {
2929
};
3030

3131
function MyComponent() {
32-
// Evaluate feature flags with useSplitTreatments hook
33-
const { treatments: { FEATURE_FLAG_NAME }, isReady } = useSplitTreatments({ names: ['FEATURE_FLAG_NAME'] });
32+
// Evaluate a feature flag with useTreatment hook
33+
const { treatment, isReady } = useTreatment({ name: 'FEATURE_FLAG_NAME' });
3434

3535
// Check SDK readiness using isReady prop
3636
if (!isReady) return <div>Loading SDK ...</div>;
3737

38-
if (FEATURE_FLAG_NAME.treatment === 'on') {
39-
// return JSX for on treatment
40-
} else if (FEATURE_FLAG_NAME.treatment === 'off') {
41-
// return JSX for off treatment
38+
if (treatment === 'on') {
39+
// return JSX for 'on' treatment
40+
} else if (treatment === 'off') {
41+
// return JSX for 'off' treatment
4242
} else {
43-
// return JSX for control treatment
43+
// return JSX for 'control' treatment
4444
};
4545
}
4646

package-lock.json

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

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@splitsoftware/splitio-react",
3-
"version": "2.5.0",
3+
"version": "2.6.0",
44
"description": "A React library to easily integrate and use Split JS SDK",
55
"main": "cjs/index.js",
66
"module": "esm/index.js",
@@ -63,7 +63,7 @@
6363
},
6464
"homepage": "https://github.com/splitio/react-client#readme",
6565
"dependencies": {
66-
"@splitsoftware/splitio": "11.7.2-rc.4",
66+
"@splitsoftware/splitio": "11.8.0",
6767
"memoize-one": "^5.1.1",
6868
"shallowequal": "^1.1.0",
6969
"tslib": "^2.3.1"

src/SplitClient.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import { useSplitClient } from './useSplitClient';
99
*
1010
* The underlying SDK client can be changed during the component lifecycle
1111
* if the component is updated with a different splitKey prop.
12-
*
13-
* @deprecated `SplitClient` will be removed in a future major release. We recommend replacing it with the `useSplitClient` hook.
1412
*/
1513
export function SplitClient(props: ISplitClientProps) {
1614
const { children } = props;

src/SplitTreatments.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { useSplitTreatments } from './useSplitTreatments';
99
* call the 'client.getTreatmentsWithConfig()' method if the `names` prop is provided, or the 'client.getTreatmentsWithConfigByFlagSets()' method
1010
* if the `flagSets` prop is provided. It then passes the resulting treatments to a child component as a function.
1111
*
12-
* @deprecated `SplitTreatments` will be removed in a future major release. We recommend replacing it with the `useSplitTreatments` hook.
12+
* @deprecated `SplitTreatments` will be removed in a future major release. We recommend replacing it with the `useTreatment*` hooks.
1313
*/
1414
export function SplitTreatments(props: ISplitTreatmentsProps) {
1515
const { children } = props;

src/__tests__/index.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ import {
1212
useSplitClient as exportedUseSplitClient,
1313
useSplitTreatments as exportedUseSplitTreatments,
1414
useSplitManager as exportedUseSplitManager,
15+
useTreatment as exportedUseTreatment,
16+
useTreatmentWithConfig as exportedUseTreatmentWithConfig,
17+
useTreatments as exportedUseTreatments,
18+
useTreatmentsWithConfig as exportedUseTreatmentsWithConfig,
1519
// Checks that types are exported. Otherwise, the test would fail with a TS error.
1620
GetTreatmentsOptions,
1721
ISplitClientChildProps,
@@ -39,6 +43,10 @@ import { useTrack } from '../useTrack';
3943
import { useSplitClient } from '../useSplitClient';
4044
import { useSplitTreatments } from '../useSplitTreatments';
4145
import { useSplitManager } from '../useSplitManager';
46+
import { useTreatment } from '../useTreatment';
47+
import { useTreatmentWithConfig } from '../useTreatmentWithConfig';
48+
import { useTreatments } from '../useTreatments';
49+
import { useTreatmentsWithConfig } from '../useTreatmentsWithConfig';
4250

4351
describe('index', () => {
4452

@@ -59,6 +67,10 @@ describe('index', () => {
5967
expect(exportedUseSplitClient).toBe(useSplitClient);
6068
expect(exportedUseSplitTreatments).toBe(useSplitTreatments);
6169
expect(exportedUseSplitManager).toBe(useSplitManager);
70+
expect(exportedUseTreatment).toBe(useTreatment);
71+
expect(exportedUseTreatmentWithConfig).toBe(useTreatmentWithConfig);
72+
expect(exportedUseTreatments).toBe(useTreatments);
73+
expect(exportedUseTreatmentsWithConfig).toBe(useTreatmentsWithConfig);
6274
});
6375

6476
it('should export SplitContext', () => {

src/__tests__/testUtils/mockSplitFactory.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { EventEmitter } from 'events';
22
import jsSdkPackageJson from '@splitsoftware/splitio/package.json';
33
import reactSdkPackageJson from '../../../package.json';
4+
import { CONTROL, CONTROL_WITH_CONFIG } from '../../constants';
45

56
export const jsSdkVersion = `javascript-${jsSdkPackageJson.version}`;
67
export const reactSdkVersion = `react-${reactSdkPackageJson.version}`;
@@ -65,6 +66,24 @@ export function mockSdk() {
6566
const track: jest.Mock = jest.fn(() => {
6667
return true;
6768
});
69+
const getTreatment: jest.Mock = jest.fn((featureFlagName: string) => {
70+
return typeof featureFlagName === 'string' ? 'on' : CONTROL;
71+
});
72+
const getTreatments: jest.Mock = jest.fn((featureFlagNames: string[]) => {
73+
return featureFlagNames.reduce((result: SplitIO.Treatments, featureName: string) => {
74+
result[featureName] = 'on';
75+
return result;
76+
}, {});
77+
});
78+
const getTreatmentsByFlagSets: jest.Mock = jest.fn((flagSets: string[]) => {
79+
return flagSets.reduce((result: SplitIO.Treatments, flagSet: string) => {
80+
result[flagSet + '_feature_flag'] = 'on';
81+
return result;
82+
}, {});
83+
});
84+
const getTreatmentWithConfig: jest.Mock = jest.fn((featureFlagName: string) => {
85+
return typeof featureFlagName === 'string' ? { treatment: 'on', config: null } : CONTROL_WITH_CONFIG;
86+
});
6887
const getTreatmentsWithConfig: jest.Mock = jest.fn((featureFlagNames: string[]) => {
6988
return featureFlagNames.reduce((result: SplitIO.TreatmentsWithConfig, featureName: string) => {
7089
result[featureName] = { treatment: 'on', config: null };
@@ -113,6 +132,10 @@ export function mockSdk() {
113132
});
114133

115134
return Object.assign(Object.create(__emitter__), {
135+
getTreatment,
136+
getTreatments,
137+
getTreatmentsByFlagSets,
138+
getTreatmentWithConfig,
116139
getTreatmentsWithConfig,
117140
getTreatmentsWithConfigByFlagSets,
118141
track,

src/__tests__/testUtils/sdkConfigs.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,11 @@ export const sdkBrowser: SplitIO.IBrowserSettings = {
44
key: 'customer-key',
55
},
66
};
7+
8+
export const sdkBrowserWithConfig: SplitIO.IBrowserSettings = {
9+
...sdkBrowser,
10+
fallbackTreatments: {
11+
global: 'control_global',
12+
byFlag: { ff1: { treatment: 'control_ff1', config: 'control_ff1_config' } }
13+
}
14+
};

0 commit comments

Comments
 (0)