-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathSplitFactory.tsx
More file actions
92 lines (80 loc) · 4.63 KB
/
SplitFactory.tsx
File metadata and controls
92 lines (80 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import React from 'react';
import { SplitComponent } from './SplitClient';
import { ISplitFactoryProps } from './types';
import { WARN_SF_CONFIG_AND_FACTORY, ERROR_SF_NO_CONFIG_AND_FACTORY } from './constants';
import { getSplitFactory, destroySplitFactory, IFactoryWithClients, getSplitClient } from './utils';
import { DEFAULT_UPDATE_OPTIONS } from './useSplitClient';
/**
* SplitFactory will initialize the Split SDK and its main client, listen for its events in order to update the Split Context,
* and automatically shutdown and release resources when it is unmounted. SplitFactory must wrap other components and functions
* from this library, since they access the Split Context and its properties (factory, client, isReady, etc).
*
* 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 `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}
*/
export class SplitFactory extends React.Component<ISplitFactoryProps, { factory: SplitIO.IBrowserSDK | null, client: SplitIO.IBrowserClient | null }> {
static defaultProps: ISplitFactoryProps = {
children: null,
...DEFAULT_UPDATE_OPTIONS,
};
readonly state: Readonly<{ factory: SplitIO.IBrowserSDK | null, client: SplitIO.IBrowserClient | null }>;
readonly isFactoryExternal: boolean;
constructor(props: ISplitFactoryProps) {
super(props);
// Log warning and error
const { factory: propFactory, config } = props;
if (!config && !propFactory) {
console.error(ERROR_SF_NO_CONFIG_AND_FACTORY);
}
if (config && propFactory) {
console.log(WARN_SF_CONFIG_AND_FACTORY);
}
// Instantiate factory
let factory = null;
if (propFactory) {
factory = propFactory;
} else {
if (config) {
// We use an idempotent variant of the Split factory builder (i.e., given the same config, it returns the same already
// created instance), since React component constructors is part of render-phase and can be invoked multiple times.
factory = getSplitFactory(config);
factory.init();
}
}
this.isFactoryExternal = propFactory ? true : false;
// Instantiate main client. Attributes are set on `SplitComponent.getDerivedStateFromProps`
const client = factory ? getSplitClient(factory) : null;
this.state = {
client,
factory,
};
}
componentWillUnmount() {
// only destroy the client if the factory was created internally. Otherwise, the shutdown must be handled by the user
if (!this.isFactoryExternal && this.state.factory) {
destroySplitFactory(this.state.factory as IFactoryWithClients);
}
}
render() {
const { factory, client } = this.state;
return (
<SplitComponent {...this.props} factory={factory} client={client} />
);
}
}