Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2296052
Update CHANGES file and comments to explain breaking changes when mig…
EmilianoSanchez Jan 26, 2024
c1803ca
Update comment regarding factory and config props in SplitFactoryProv…
EmilianoSanchez Jan 26, 2024
6105b3f
Nico's feedback: 'Notable changes' rather than 'Breaking changes'
EmilianoSanchez Jan 30, 2024
11e01ae
Team's feedback: add MIGRATION-GUIDE.md file
EmilianoSanchez Jan 30, 2024
4d88095
Team's feedback: add MIGRATION-GUIDE.md file
EmilianoSanchez Jan 31, 2024
50b5028
Polishing
EmilianoSanchez Feb 2, 2024
40fdfe1
Lena's feedback
EmilianoSanchez Feb 2, 2024
af8066d
Rollback header links (not working as expected)
EmilianoSanchez Feb 2, 2024
2bbe2ca
Lena's feedback
EmilianoSanchez Feb 2, 2024
ceac3a7
Add migration example for SplitFactoryProvider
EmilianoSanchez Feb 2, 2024
06aedbc
Merge branch 'migration-guide' into breaking-changes-explanation
EmilianoSanchez Feb 2, 2024
eee6e11
Polishing
EmilianoSanchez Feb 2, 2024
f0b6978
Add comment regarding manager property
EmilianoSanchez Feb 2, 2024
8be63a9
Merge branch 'migration-guide' into breaking-changes-explanation
EmilianoSanchez Feb 2, 2024
d28e3eb
Polishing
EmilianoSanchez Feb 2, 2024
fb36783
Update MIGRATION-GUIDE.md
EmilianoSanchez Feb 2, 2024
ed85e6b
Merge branch 'breaking-changes-explanation' into migration-guide
EmilianoSanchez Feb 2, 2024
d8a77bf
Formatting
EmilianoSanchez Feb 2, 2024
03c7bc9
Merge pull request #188 from splitio/migration-guide
EmilianoSanchez Feb 2, 2024
6c10873
Add tslib as a dependency explicitly
EmilianoSanchez Mar 22, 2024
136814d
ci-cd update for UMD build
EmilianoSanchez Mar 25, 2024
825a502
prepare stable version
EmilianoSanchez Mar 26, 2024
21e44d1
Merge pull request #189 from splitio/release_v1.11.1
EmilianoSanchez Mar 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
1.11.0 (January 16, 2023)
- Added the new `SplitFactoryProvider` component as a replacement for the now deprecated `SplitFactory` component.
The new component is a revised version of `SplitFactory`, addressing improper handling of the SDK initialization side-effects in the `componentDidMount` and `componentDidUpdate` methods (commit phase), causing some issues like memory leaks and the SDK not reinitializing when component props change (Related to issue #11 and #148).
The `SplitFactoryProvider` component can be used as a drop-in replacement for `SplitFactory`. It utilizes the React Hooks API, that requires React 16.8.0 or later, and supports server-side rendering. See our documentation for more details (Related to issue #11 and #109).
1.11.1 (March 26, 2024)
- Bugfixing - Added tslib as an explicit dependency to avoid issues with some package managers that don't resolve it automatically as a transitive dependency from @splitsoftware/splitio-commons (Related to issue https://github.com/splitio/javascript-client/issues/795).

1.11.0 (January 16, 2024)
- Added new `SplitFactoryProvider` component as a replacement for the now deprecated `SplitFactory` component.
- Bugfixing: The new component is a revised version of `SplitFactory` that properly handles SDK side effects (i.e., factory creation and destruction) within the React component lifecycle,
- resolving memory leak issues in React development mode, strict mode and server-side rendering (Related to issues #11 and #109),
- and also ensuring that the SDK is updated if `config` or `factory` props change (Related to issues #11 and #148).
- Notable changes when migrating from `SplitFactory` to `SplitFactoryProvider`:
- `SplitFactoryProvider` utilizes the React Hooks API, requiring React 16.8.0 or later, while `SplitFactory` is compatible with React 16.3.0 or later.
- When using the `config` prop with `SplitFactoryProvider`, the `factory` and `client` properties in `SplitContext` and the `manager` property in `useSplitManager` results are `null` in the first render, until the context is updated when some event is emitted on the SDK main client (ready, ready from cache, timeout, or update, depending on the configuration of the `updateOn<Event>` props of the component). This differs from the previous behavior where `factory`, `client`, and `manager` were immediately available.
- Updating the `config` prop in `SplitFactoryProvider` reinitializes the SDK with the new configuration, while `SplitFactory` does not reinitialize the SDK. You should pass a reference to the configuration object (e.g., via a global variable, `useState`, or `useMemo`) rather than a new instance on each render, to avoid unnecessary reinitializations.
- Updating the `factory` prop in `SplitFactoryProvider` replaces the current SDK instance, unlike `SplitFactory` where it is ignored.
- Updated internal code to remove a circular dependency and avoid warning messages with tools like PNPM (Related to issue #176).
- Updated @splitsoftware/splitio package to version 10.25.1 for vulnerability fixes.

Expand Down
142 changes: 142 additions & 0 deletions MIGRATION-GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@

# Migrating to get React SDK v1.11.0 improvements: Replacing the deprecated `SplitFactory` and `withSplitFactory` components

Starting from React SDK v1.11.0, the `SplitFactoryProvider` component is available and can replace the older `SplitFactory` and `withSplitFactory` components. The deprecated components will continue working, until they are removed in a future major release.

We recommend migrating to the new `SplitFactoryProvider` component instead. This component is a revised version of `SplitFactory` that properly handles SDK side effects (i.e., factory creation and destruction) within the React component lifecycle. By migrating, you can benefit from a number of improvements:

- Resolution of memory leak issues in React development mode, strict mode, and server-side rendering.

- Updating the SDK when `config` or `factory` props change.

Notable changes to consider when migrating:
- `SplitFactoryProvider` utilizes the React Hooks API, requiring React 16.8.0 or later, while `SplitFactory` is compatible with React 16.3.0 or later.

- When using the `config` prop with `SplitFactoryProvider`, the `factory` and `client` properties in `SplitContext` and the `manager` property in `useSplitManager` results are `null` in the first render, until the context is updated when some event is emitted on the SDK main client (ready, ready from cache, timeout, or update, depending on the configuration of the `updateOn<Event>` props of the component). This differs from the previous behavior where `factory`, `client`, and `manager` were immediately available. Nonetheless, it is not recommended to use the `client` and `factory` properties directly as better alternatives are available. For example, use the `useTrack` and `useSplitTreatments` hooks rather than the client's `track` and `getTreatments` methods.

- Updating the `config` prop in `SplitFactoryProvider` reinitializes the SDK with the new configuration, while `SplitFactory` does not reinitialize the SDK. You should pass a reference to the configuration object (e.g., via a global variable, `useState`, or `useMemo`) rather than a new instance on each render, to avoid unnecessary reinitializations.

- Updating the `factory` prop in `SplitFactoryProvider` replaces the current SDK instance, unlike `SplitFactory` where it is ignored.

To migrate your existing code, replace:

```javascript
const MyApp = () => {
return (
<SplitFactory config={mySplitConfig}>
<MyComponent />
</SplitFactory>
);
};
```

or

```javascript
const MyApp = withSplitFactory(mySplitConfig)(MyComponent);
```

with:

```javascript
const MyApp = () => {
return (
<SplitFactoryProvider config={mySplitConfig}>
<MyComponent />
</SplitFactoryProvider>
);
};
```

and consider that `factory`, `client` and `manager` properties might be `null` until the SDK has emitted some event:

```javascript
const MyComponent = () => {
// factoryFromContext === factory, clientFromContext === client, and they are null until some SDK event is emitted
const { factory: factoryFromContext, client: clientFromContext } = useContext(SplitContext);
const { factory, client } = useSplitClient();

// Example to evaluate all your flags when the SDK is ready and re-evaluate on SDK_UPDATE events
const { manager } = useSplitManager();
const FEATURE_FLAG_NAMES = manager ? manager.names() : [];
const { treatments, isReady } = useSplitTreatments({ names: FEATURE_FLAG_NAMES, updateOnSdkUpdate: true }); // updateOnSdkReady is true by default

return isReady ?
treatments['feature-flag-1'].treatment === 'on' ?
<FeatureOn /> :
<FeatureOff /> :
<LoadingPage />
}
```

# Migrating to get React SDK v1.10.0 improvements: Replacing the deprecated `useClient`, `useTreatments`, and `useManager` hooks

Starting from React SDK v1.10.0, the `useSplitClient`, `useSplitTreatments`, and `useSplitManager` hooks are available and can replace the older `useClient`, `useTreatments`, and `useManager` hooks respectively. The deprecated hooks will continue working, until they are removed in a future major release.

We recommend migrating to the new versions `useSplitClient`, `useSplitTreatments` and `useSplitManager` respectively, which provide a more flexible API:

- They accept an options object as parameter, instead of a list of parameters as their deprecated counterparts. The options object can contain the same parameters as the old hooks, plus some extra optional parameters: `updateOnSdkReady`, `updateOnSdkReadyFromCache`, `updateOnSdkTimedout`, and `updateOnSdkUpdate`, which control when the hook updates the component. For example, you can set `updateOnSdkUpdate` to `true`, which is `false` by default, to update the component when an `SDK_UPDATE` event is emitted. This is useful when you want to avoid unnecessary re-renders of your components.

- They return an object containing the SDK status properties. These properties are described in the ['Subscribe to events and changes' section](https://help.split.io/hc/en-us/articles/360038825091-React-SDK#subscribe-to-events-and-changes) and enable conditional rendering of components based on the SDK status, eliminating the need to access the Split context or use the client's `ready` promise or event listeners. For example, you can show a loading spinner until the SDK is ready, and use the `treatments` result to render the variants of your app once the SDK is ready.

The usage of the new hooks is shown below:

```js
const { client, isReady, isReadyFromCache, hasTimedout, lastUpdate } = useSplitClient({ splitKey: userId, updateOnSdkUpdate: true });
const { treatments, isReady, isReadyFromCache, hasTimedout, lastUpdate } = useSplitTreatments({ names: ['feature-flag-1'], updateOnSdkTimedout: false });
const { manager, isReady, isReadyFromCache, hasTimedout, lastUpdate } = useSplitManager();
```



To migrate your existing code, replace:

```javascript
const client = useClient(optionalSplitKey, optionalTrafficType, optionalAttributes);
const treatments = useTreatments(featureFlagNames, optionalAttributes, optionalSplitKey);
const manager = useManager();
```

with:

```javascript
const { client } = useSplitClient({ splitKey: optionalSplitKey, trafficType: optionalTrafficType, attributes: optionalAttributes });
const { treatments } = useSplitTreatments({ names: featureFlagNames, attributes: optionalAttributes, splitKey: optionalSplitKey });
const { manager } = useSplitManager();
```

and use the status properties to conditionally render your components. For example, use the following code:

```javascript
const MyComponent = ({ userId }) => {

const { treatments, isReady } = useSplitTreatments({ names: [FEATURE_X], splitKey: userId })

return isReady ?
treatments[FEATURE_X].treatment === 'on' ?
<FeatureOn /> :
<FeatureOff /> :
<LoadingPage />
}
```

instead of:

```javascript
const MyComponent = ({ userId }) => {

const [sdkIsReady, setSdkIsReady] = useState(false);
const client = useClient(userId);
const treatments = useTreatments([FEATURE_X], undefined, userId);

useEffect(() => {
if (client) client.ready().then(() => setSdkIsReady(true));
}, [client]);

return isReady ?
treatments[FEATURE_X].treatment === 'on' ?
<FeatureOn /> :
<FeatureOff /> :
<LoadingPage />
}
```
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,15 @@ 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)
* 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)
* Java [Github](https://github.com/splitio/java-client) [Docs](https://help.split.io/hc/en-us/articles/360020405151-Java-SDK)
* JavaScript [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK)
* JavaScript for Browser [Github](https://github.com/splitio/javascript-browser-client) [Docs](https://help.split.io/hc/en-us/articles/360058730852-Browser-SDK)
* Node [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK)
* PHP [Github](https://github.com/splitio/php-client) [Docs](https://help.split.io/hc/en-us/articles/360020350372-PHP-SDK)
* PHP thin-client [Github](https://github.com/splitio/php-thin-client) [Docs](https://help.split.io/hc/en-us/articles/18305128673933-PHP-Thin-Client-SDK)
* Python [Github](https://github.com/splitio/python-client) [Docs](https://help.split.io/hc/en-us/articles/360020359652-Python-SDK)
* React [Github](https://github.com/splitio/react-client) [Docs](https://help.split.io/hc/en-us/articles/360038825091-React-SDK)
* React Native [Github](https://github.com/splitio/react-native-client) [Docs](https://help.split.io/hc/en-us/articles/4406066357901-React-Native-SDK)
Expand Down
23 changes: 13 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{
"name": "@splitsoftware/splitio-react",
"version": "1.11.0",
"version": "1.11.1",
"description": "A React library to easily integrate and use Split JS SDK",
"main": "lib/index.js",
"module": "es/index.js",
"types": "types/index.d.ts",
"files": [
"README.md",
"CONTRIBUTORS-GUIDE.md",
"MIGRATION-GUIDE.md",
"LICENSE",
"CHANGES.txt",
"src",
Expand Down Expand Up @@ -62,9 +63,10 @@
},
"homepage": "https://github.com/splitio/react-client#readme",
"dependencies": {
"@splitsoftware/splitio": "10.25.1",
"@splitsoftware/splitio": "10.25.2",
"memoize-one": "^5.1.1",
"shallowequal": "^1.1.0"
"shallowequal": "^1.1.0",
"tslib": "^2.3.1"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
Expand Down
17 changes: 13 additions & 4 deletions src/SplitFactory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,19 @@ import { DEFAULT_UPDATE_OPTIONS } from './useSplitClient';
* The underlying SDK factory and client is set on the constructor, and cannot be changed during the component lifecycle,
* even if the component is updated with a different config or factory prop.
*
* @deprecated Replace with the new `SplitFactoryProvider` component.
* `SplitFactoryProvider` is a drop-in replacement that properly handles side effects (factory creation and destruction) within the React component lifecycle, avoiding issues with factory recreation and memory leaks.
* Note: There is a subtle breaking change in `SplitFactoryProvider`. When using the `config` prop, `factory` and `client` properties in the context are `null` in the first render, until the context is updated when some event is emitted on
* the SDK main client (ready, ready from cache, timeout or update depending on the configuration of the `updateOnXXX` props of the component). This differs from the previous behavior where `factory` and `client` were immediately available.
* @deprecated `SplitFactory` will be removed in a future major release. We recommend replacing it with the new `SplitFactoryProvider` component.
*
* `SplitFactoryProvider` is a revised version of `SplitFactory` that properly handles SDK side effects (i.e., factory creation and destruction) within the React component lifecycle,
* resolving memory leak issues in React development mode, strict mode and server-side rendering, and also ensuring that the SDK is updated if `config` or `factory` props change.
*
* Notable changes to consider when migrating:
* - `SplitFactoryProvider` utilizes the React Hooks API, requiring React 16.8.0 or later, while `SplitFactory` is compatible with React 16.3.0 or later.
* - When using the `config` prop with `SplitFactoryProvider`, the `factory` and `client` properties in `SplitContext` and the `manager` property in `useSplitManager` results
* are `null` in the first render, until the context is updated when some event is emitted on the SDK main client (ready, ready from cache, timeout, or update, depending on
* the configuration of the `updateOn<Event>` props of the component). This differs from the previous behavior where `factory`, `client`, and `manager` were immediately available.
* - Updating the `config` prop in `SplitFactoryProvider` reinitializes the SDK with the new configuration, while `SplitFactory` does not reinitialize the SDK. You should pass a
* reference to the configuration object (e.g., via a global variable, `useState`, or `useMemo`) rather than a new instance on each render, to avoid unnecessary reinitializations.
* - Updating the `factory` prop in `SplitFactoryProvider` replaces the current SDK instance, unlike `SplitFactory` where it is ignored.
*
* @see {@link https://help.split.io/hc/en-us/articles/360038825091-React-SDK#2-instantiate-the-sdk-and-create-a-new-split-client}
*/
Expand Down
Loading