React/React Native (Client-Side) SDK
Introduction
Welcome to the developer documentation for the Kameleoon React SDK! Our SDK gives you the possibility of running experiments and activating feature flags on your front-end React/React Native application. Integrating our SDK into your web-application is easy, and its footprint (in terms of memory and network usage) is low.
React SDK provides functionality that can be used for both React and React Native. Most of the methods work the exact same way, however React Native uses different way of storing feature flag related data - AsyncStorage
instead of browser localStorage
, taking in consideration that all the calls to AsyncStorage
has to be asynchronous, some methods has to be handled in a different way.
Requirements
React SDK requires React 16.8.0+
Installation
npm install @kameleoon/react-sdk
yarn add @kameleoon/react-sdk
Installing the React SDK can be directly achieved through an npm
or yarn
module:
Contents
Follow the Usage section to configure your React App for work with feature flags. This section contains all the main steps for proper Kameleoon React SDK configuration as well as main tools for development.
- 1. Create and configure Kameleoon Client
- 2. Wrap application in Kameleoon Provider
- 3. Get access to feature flag inside React Components.
- 4. (Optional) Use Kameleoon Client directly.
Optionally discover Additional Tools section containing useful information on a number of features, some useful utility hooks and higher-order components which will simplify the usage of React JS SDK.
- Variation Associated Data
- Local Storage Key
- Visitor Code
- Trigger an Experiment
- Feature Variables
- Track Conversion
- Retrieve Data from Remote Source
- Add User Data
- Data Flush
- Data Structure
- Compose
Finally Technical Considerations section presents some technical insights on how SDK operates.
Usage
Here is a step by step guide for configuring React JS SDK for your application.
1. Create and configure Kameleoon Client
For the start developers will need to create an entry point for React SDK by creating Kameleoon Client on the top level of your application which is done by using createClient()
function imported from kameleoon package.
createClient
import { createClient } from "@kameleoon/react-sdk";
const client = createClient({
siteCode: "0fpmcg34lg",
visitorCode: "280295",
options: {
visitor_data_maximum_size: 1,
actions_configuration_refresh_interval: 60,
environment: 'staging'
},
});
A KameleoonClient
is created using createClient()
callback function to run experiments and retrieve the status of feature flag and its variables.
Arguments
clientParams: ICreateClientParams
- an object with arguments for client configuration.siteCode: string
(required) - code of the website which experiments run on. This unique code id can be found in our platform.visitorCode: string
(optional) - visitor code is an optional parameter, if it is used, it automatically create custom data to check if visitor is targeted.option: SDKConfiguration
(optional) - JSON object filled with configuration parameters.actions_configuration_refresh_interval: number
(optional) - specifies the refresh interval (in minutes) of the configuration for experiments and feature flags (the active experiments and feature flags are fetched from the Kameleoon servers). It means that once you launch an experiment, pause it, or stop it the changes can take (at most) the duration of this interval to be propagated in production to your servers. If not specified, the default interval is 60 minutes.visitor_data_maximum_size: number
(optional) - specifies the maximum amount of memory that the map holding all the visitor data (in particular custom data) can take (in MB on the browser LocalStorage). If specified, max size is 5MB. If not specified, the default size is 1MB.environment: string
(optional) - an option specifying which feature flag configuration will be used, by default each feature flag is split into production, staging, development. If not specified, will be set to default value of production.
Returns
- A
KameleoonClient
instance.
Types
ICreateClientParams
- an interface imported from"@kameleoon/react-sdk"
, which describes configuration object forcreateClient()
.
2. Wrap application in Kameleoon Provider
The second step is connecting previously created Kameleoon Client to Kameleoon Provider
. It can be done by passing configured client to Kameleoon Provider
as follows.
KameleoonProvider
import { KameleoonProvider, createClient } from '@kameleoon/react-sdk';
const client = createClient({
siteCode: '0fpmcg34lg'
visitorCode: '280295',
options: {
visitor_data_maximum_size: 1,
actions_configuration_refresh_interval: 60,
environment: 'staging'
}
});
function AppWrapper(): JSX.Element {
return (
<KameleoonProvider client={client}>
<App />
</KameleoonProvider>
)
}
Use this provider on root level by wrapping your app to gain an access to KameleoonClient
. This ensures your app does not flicker due to flag changes at startup time.
Props
children: ReactNode
- child elements of the provider.client: KameleoonClient
-KameleoonClient
instance created bycreateClient()
.
Types
ICreateClientParams
- an interface imported from"@kameleoon/react-sdk"
, which describes configuration object forcreateClient()
.
3. Get access to feature flag inside React Components.
Now that Kameleoon Client
is created, configured and added to a Kameleoon Provider
it is possible to communicate with your feature flag from the inside of React Components.
There are two main ways in React SDK API that allow developer to grant control over the most important feature flag information useActivateFeature
and useFeature
hooks.
useActivateFeature
- returns a function that, provided with feature key and visitor code gives a basic information on feature flag (whether the feature is active or not).useFeature
- is the superset ofuseActivateFeature
, unlikeuseActivateFeature
it requires parameters to be passed to hook itself and then, in addition to the feature flag information, it can also return feature variables which were setup in Kameleoon Web Application.
Further is the detailed description on the usage of hooks and higher order component for gaining access to useActivateFeature
and useFeature
.
useActivateFeature
import { useEffect } from 'react';
import { useActivateFeature, useVisitorCode, KameleoonException } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { hasFeature, error } = useActivateFeature();
const { getVisitorCode } = useVisitorCode();
useEffect(() => {
const visitorCode = getVisitorCode('example.com');
const featureKey = 'example-feature-key';
if (error?.type === KameleoonException.NotTargeted) {
// Handle error
}
if (error?.type === KameleoonException.FeatureConfigurationNotFound) {
// Handle error
}
const feature = hasFeature(featureKey, visitorCode);
}, []);
...
}
A hook that returns a callback function hasFeature()
which validates if user has been associated with this feature along with an error
object. If the callback fails, it returns value false, otherwise true.
If feature flag is not activated, KameleoonException.FeatureConfigurationNotFound
exception will be thrown.
Callback arguments
featureKey: string | number
(required) - unique identifier or key of the feature you want to expose to a user.visitorCode: string
(required) - unique identifier of the user, which can either be generated manually or via specialuseVisitorCode
hook.
Callback returns
- A
value: boolean
of the feature that is registered for a givenvisitorCode
.
Exceptions Thrown
KameleoonException.NotTargeted
- Exception indicating that the current visitor / user did not trigger the required targeting conditions for this feature. The targeting conditions are defined via Kameleoon's segment builder.KameleoonException.FeatureConfigurationNotFound
- Exception indicating that the requested feature ID has not been found in the internal configuration of the SDK. This is usually normal and means that the feature flag has not yet been activated on Kameleoon's side (but code implementing the feature is already deployed on the web-application's side).
Error Handling
An error
object returned from the hook contains message: string
, name: string
and type: KameleoonException
fields. A type
key may be useful for comparing the returned error type against KameleoonException
enum. If there were no errors error
will be null
.
Types
KameleoonError
- an error object type.KameleoonException
- an enum containing all the possibleKameleoonError
types.
useFeature
import { Button } from "@kameleoon/ui";
import { useFeature, useVisitorCode, KameleoonException } from "@kameleoon/react-sdk";
function MyComponent(): JSX.Element {
const { getVisitorCode } = useVisitorCode();
const { feature, errors } = useFeature({
featureKey: "red-button",
variableKeys: { production: 'red-button' },
visitorCode: getVisitorCode("example.com"),
});
for (const error of errors) {
if (error.type === KameleoonException.NotTargeted) {
// Handle error
}
if (error.type === KameleoonException.FeatureConfigurationNotFound) {
// Handle error
}
}
const { isActive, variables } = feature;
return <Button theme={isActive ? "red" : "green"} />;
}
A hook that returns feature
object containing the information on both feature flag status and the list of variables along with an errors
object, containing a list of kameleoon client errors. If not provided with visitorCode, will automatically generate one.
Arguments
featureParams: IFeatureParams
featureKey: string | number
(required) - unique identifier or key of the feature you want to expose to a user.variableKeys: VariableKeysType
(required) - keys for the variables on different environments.visitorCode: string
(optional) - unique identifier of the user.
Returns
An object featureResult
containing feature flag information and errors
array of kameleoon client errors.
feature: IFeature
isActive: boolean
- feature flag status.variables: FeatureVariableType[]
- feature flag variables.
errors: KameleoonError[]
In the examples, if the feature flag with the red-button
key is enabled, theme of button will set to red.
Exceptions Thrown
KameleoonException.NotTargeted
- Exception indicating that the current visitor / user did not trigger the required targeting conditions for this feature. The targeting conditions are defined via Kameleoon's segment builder.KameleoonException.FeatureConfigurationNotFound
- Exception indicating that the requested feature ID has not been found in the internal configuration of the SDK. This is usually normal and means that the feature flag has not yet been activated on Kameleoon's side (but code implementing the feature is already deployed on the web-application's side).
Error Handling
An errors
array returned from the hook contains a list of KameleoonError
. Each errors' type
key may be useful for comparing the returned error type against KameleoonException
enum. If there were no errors errors
array will be empty.
Types
IFeatureParams
- an interface foruseVisitorCode
configuration object.IFeature
- an interface forfeature
object returned byuseVisitorCode
.KameleoonError
- an error object type.KameleoonException
- an enum containing all the possibleKameleoonError
types.
withActivateFeature
import { withVisitorCode, withActivateFeature, compose, KameleoonException } from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { getVisitorCode, hasFeature, activateFeatureError } = this.props;
const visitorCode = getVisitorCode('example.com');
const featureKey = 'example-feature-key';
if (activateFeatureError?.type === KameleoonException.NotTargeted) {
// Handle error
}
if (activateFeatureError?.type === KameleoonException.FeatureConfigurationNotFound) {
// Handle error
}
const feature = hasFeature(featureKey, visitorCode);
}
...
}
export default compose(withVisitorCode, withActivateFeature)(MyComponent);
An alternative of useActivateFeature
for React Class Components.
Returns
- A wrapped component with additional props as described above.
Error Handling
Unlike useActivateFeature
hook, which retrieves and error
object, withActivateFeature
HOC enhances props with named activateFeatureError
error to avoid error naming intersection when using several HOCs within compose
.
withFeature
import { Button } from "@kameleoon/ui";
import { withFeature, KameleoonException } from "@kameleoon/react-sdk";
class MyComponent extends React.Component {
state = {
isActive: false,
variables: [],
}
componentDidMount() {
const { feature, errors } = this.props;
for (const error of errors) {
if (error.type === KameleoonException.NotTargeted) {
// Handle error
}
if (error.type === KameleoonException.FeatureConfigurationNotFound) {
// Handle error
}
}
const { isActive, variables } = feature;
this.setState({ isActive, variables });
}
render() {
return <Button theme={isActive ? "red" : "green"} />;
}
}
export default withFeature({
featureKey: "red-button",
variableKeys: { production: 'red-button' },
visitorCode: "280295",
})(MyComponent);
An alternative for useFeature
for React Class Components.
Arguments
featureParams: IFeatureParams
featureKey: string | number
(required) - unique identifier or key of the feature you want to expose to a user.variableKeys: VariableKeysType
(required) - keys for the variables on different environments.visitorCode: string
(required) - unique identifier of the user.
Returns
feature: IFeature
isActive: boolean
- feature flag status.variables: FeatureVariableType[]
- feature flag variables.
errors: KameleoonError[]
In the examples, if the feature flag with the red-button
key is enabled, theme of button will set to red.
Feature
import { Button } from '@kameleoon/ui';
import { Feature } from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
state = {
isActive: false,
variables: [],
}
componentDidMount() {
const { feature, errors } = this.props;
for (const error of errors) {
if (error.type === KameleoonException.NotTargeted) {
// Handle error
}
if (error.type === KameleoonException.FeatureConfigurationNotFound) {
// Handle error
}
}
const { isActive, variables } = feature;
this.setState({ isActive, variables });
}
render() {
return <Button theme={this.isActive ? 'red' : 'green'} />;
}
}
class MyComponentWrapper extends React.Component {
render() {
return(
<Feature
featureKey="red-button"
variableKeys={{production: "red-button"}}
visitorCode="280295"
>
(({ feature, errors }) => (
<MyComponent feature={feature} errors={errors} />
))
</Feature>;
)
}
}
An alternative for useFeature
and withFeature
which utilizes React Render Props pattern.
Props
children: (featureResult: IFeature) => ReactNode
- child elements ofFeature
.featureKey: string | number
- unique identifier or key of the feature you want to expose to a user.variableKeys: VariableKeysType
- keys for the variables on different environments.visitorCode: string
- unique identifier of the user.
Returns
A wrapped component with the following props:
errors: KameleoonException[]
- an array of errors thrown as a result of getting variables or feature flag status.feature
- an object containing feature flag status and variablesisActive: boolean
- feature flag status.variables: FeatureVariableType[]
- feature flag variables.
In the examples, if the feature flag with the red-button
key is enabled, theme of button will set to red.
4. (Optional) Use Kameleoon Client directly.
React JS SDK allows the developer to communicate with Kameleoon JS/TS sdk directly ignoring existing hooks and HOCs methods.
useKameleoon
import { useKameleoon } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { client } = useKameleoon();
...
}
Gives direct access to Kameleoon JS/TS client.
Returns
object: KameleoonHookResult
:client: KameleoonClient
- an instance ofKameleoonClient
taken from context.
withKameleoon
import { withKameleoon } from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { client } = this.props;
}
...
}
export default withKameleoon(MyComponent);
An alternative to useKameleoon
, gives direct access to Kameleoon JS/TS client.
Returns
Component: React.Component
- component which will be enhanced with the propclient: KameleoonClient
.
Additional Tools
Variation Associated Data
A callback function getVariationAssociatedData()
retrieved via useVariationAssociatedData
or withVariationAssociatedData
obtains JSON data associated with a variation. The JSON data usually represents some metadata of the variation, and can be configured on our web application interface or via our Automation API.
useVariationAssociatedData
import { useEffect } from 'react';
import { useVariationAssociatedData, KameleoonException } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { getVariationAssociatedData } = useVariationAssociatedData();
useEffect(() => {
const variationId = 280295;
if (error?.type === KameleoonException.VariationConfigurationNotFound) {
// Handle error
}
const data = getVariationAssociatedData(variationId);
}, []);
...
}
Callback function getVariationAssociatedData
takes the variationId
as a parameter and will return the data as a JavaScript object along with an error
object. It will throw an exception (KameleoonException.VariationConfigurationNotFound)
if the variationId
is wrong or corresponds to an experiment that is not yet online.
Callback Arguments
variationId: number
(required) - unique identifier of the variation you want to obtain associated data for (default value is 0).
Callback Returns
- Data associated with this
variationId
.
Exceptions Thrown
KameleoonException.VariationConfigurationNotFound
- Exception indicating that the requested variation ID has not been found in the internal configuration of the SDK. This is usually normal and means that the variation's corresponding experiment has not yet been activated on Kameleoon's side.
Error Handling
An error
object returned from the hook contains message: string
, name: string
and type: KameleoonException
fields. A type
key may be useful for comparing the returned error type against KameleoonException
enum. If there were no errors error
will be null
.
Types
KameleoonError
- an error object type.KameleoonException
- an enum containing all the possibleKameleoonError
types.
withVariationAssociatedData
import { withVariationAssociatedData, KameleoonException } from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { getVariationAssociatedData, variationAssociatedDataError } = this.props;
const variationId = 280295;
if (variationAssociatedDataError?.type === KameleoonException.VariationConfigurationNotFound) {
// Handle error
}
const data = getVariationAssociatedData(variationId);
}
...
}
export default withVariationAssociatedData(MyComponent);
An alternative for useVariationAssociatedData
.
Arguments
Component: React.Component
- component which will be enhanced with the propgetVariationAssociatedData()
.
Returns
- A wrapped component with additional props as described above.
Error Handling
Unlike useVariationAssociatedData
hook, which retrieves and error
object, withVariationAssociatedData
HOC enhances props with named variationAssociatedDataError
error to avoid error naming intersection when using several HOCs within compose
.
Local Storage Key
import { KAMELEOON_SDK_LOCAL_STORAGE_KEY } from "@kameleoon/react-sdk";
KAMELEOON_SDK_LOCAL_STORAGE_KEY
- is a constant which used as a key in LocalStorage
to store a kameleoonTargetingData
and kameleoonConfiguration
.
Visitor Code
A callback function getVisitorCode()
retrieved by useVisitorCode
or withVisitorCode
obtains the Kameleoon visitorCode
for the current visitor. This is especially important when using Kameleoon in a mixed front-end and back-end environment, where user identification consistency must be guaranteed. The implementation logic:
First we check if a
kameleoonVisitorCode
cookie can be found. If so, we will use this as the visitor identifier.If no cookie was found, we either randomly generate a new identifier, or use the
defaultVisitorCode
argument as identifier if it is passed. This allows our customers to use their own identifiers as visitor codes, should they wish to. This can have the added benefit of matching Kameleoon visitors with their own users without any additional look-ups in a matching table.In any case, the JavaScript
kameleoonVisitorCode
cookie is set with the value. Then this identifier value is finally returned by the method.
For more information, refer to this article.
useVisitorCode
import { useEffect } from 'react';
import { uuidv4 } from 'uuid';
import { useVisitorCode } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { getVisitorCode } = useVisitorCode();
useEffect(() => {
// Without defaultVisitorCode argument
const visitorCode = getVisitorCode('example.com');
// With defaultVisitorCode argument
const visitorCode = getVisitorCode('example.com', uuidv4());
}, []);
...
}
useVisitorCode
returns a callback function getVisitorCode()
used to obtain visitor code.
Callback Arguments
topLevelDomain: string
(required) - current top level domain for the concerned site (this information is needed to set the corresponding cookie accordingly, on the top level domain).defaultVisitorCode: string
(optional) - This parameter will be used as thevisitorCode
if no existingkameleoonVisitorCode
cookie is found on the request. This field is optional, and by default a randomvisitorCode
will be generated.
Callback Returns
visitorCode: string
- a visitorCode that will be associated with this particular user and should be used with most of the methods of the SDK.
withVisitorCode
import { uuidv4 } from 'uuid';
import { withVisitorCode } from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { getVisitorCode } = this.props;
// Without defaultVisitorCode argument
const visitorCode = getVisitorCode('example.com');
// With defaultVisitorCode argument
const visitorCode = getVisitorCode('example.com', uuidv4());
}
...
}
export default withVisitorCode(MyComponent);
An alternative for useVisitorCode
hook.
Arguments
Component: React.Component
- component which will be enhanced with the propgetVisitorCode()
.
Returns
- A wrapped component with additional props as described above.
Trigger an Experiment
A callback function getVariationId()
retrieved via useTriggerExperiment
or useTriggerExperiment
takes visitorCode
and experimentId
as mandatory arguments to register a variation for a given user.
If such a user has never been associated with any variation, the SDK returns a randomly selected variation. If a user with a given visitorCode
is already registered with a variation, it will detect the previously registered variation and return the variationId
.
You have to make sure that proper error handling is set up in your code as shown in the example to the right to catch potential exceptions.
Please Note:
useTriggerExperiment
import { useEffect } from 'react';
import { useTriggerExperiment, useVisitorCode, KameleoonException } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { getVariationId, error } = useTriggerExperiment();
const { getVisitorCode } = useVisitorCode();
useEffect(() => {
const visitorCode = getVisitorCode('example.com');
const experimentId = 12341;
if (error?.type === KameleoonException.ExperimentConfigurationNotFound) {
// Handle exception
}
if (error?.type === KameleoonException.NotTargeted) {
// Handle exception
}
if (error?.type === KameleoonException.NotActivated) {
// Handle exception
}
const variationId = getVariationId(visitorCode, experimentId);
}, []);
...
}
useTriggerExperiment
hook returns getVisitorCode()
function used for triggering an experiment along with an error
object.
Callback Arguments
visitorCode: string
(required) - unique identifier of the userexperimentId: number
(required) - unique identifier of the experiment you want to expose to a user
Callback Returns
variationId: number
- ID of the variation that is registered for a given visitorCode. By convention, the reference (original variation) always has an ID equal to 0.
Exceptions Thrown
KameleoonException.NotTargeted
- Exception indicating that the current visitor / user did not trigger the required targeting conditions for this experiment. The targeting conditions are defined via Kameleoon's segment builder.KameleoonException.NotActivated
- Exception indicating that the current visitor / user triggered the experiment (met the targeting conditions), but did not activate it. The most common reason for that is that part of the traffic has been excluded from the experiment and should not be tracked.KameleoonException.ExperimentConfigurationNotFound
- Exception indicating that the requested experiment ID has not been found in the internal configuration of the SDK. This is usually normal and means that the experiment has not yet been started on Kameleoon's side (but code triggering / implementing variations is already deployed on the web-application's side).
Error Handling
An error
object returned from the hook contains message: string
, name: string
and type: KameleoonException
fields. A type
key may be useful for comparing the returned error type against KameleoonException
enum. If there were no errors error
will be null
.
Types
KameleoonError
- an error object type.KameleoonException
- an enum containing all the possibleKameleoonError
types.
withTriggerExperiment
import { withVisitorCode, withTriggerExperiment, compose, KameleoonException } from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { getVisitorCode, getVariationId, triggerExperimentError } = this.props;
const visitorCode = getVisitorCode('example.com');
const experimentId = 230243;
if (triggerExperimentError?.type === KameleoonException.ExperimentConfigurationNotFound) {
// Handle exception
}
if (triggerExperimentError?.type === KameleoonException.NotTargeted) {
// Handle exception
}
if (triggerExperimentError?.type === KameleoonException.NotActivated) {
// Handle exception
}
const variationId = getVariationId(visitorCode, experimentId);
}
...
}
export default compose(withVisitorCode, withTriggerExperiment)(MyComponent);
An alternative for useTriggerExperiment
hook.
Arguments
Component: React.Component
- component which will be enhanced with the propgetVariationId()
.
Returns
- A wrapped component with additional props as described above.
Error Handling
Unlike useTriggerExperiment
hook, which retrieves and error
object, withTriggerExperiment
HOC enhances props with named triggerExperimentError
error to avoid error naming intersection when using several HOCs within compose
.
Feature Variables
A callback function getFeatureVariable()
retrieved by useFeatureVariable
or withFeatureVariable
is used to obtain a feature variable.
This callback function takes two input parameters: featureKey
and variableKey
. It will return the data with the expected type, as defined on the web interface. It will throw an exception (KameleoonException.FeatureConfigurationNotFound)
if the requested feature has not been found in the internal configuration of the SDK.
useFeatureVariable
import { useEffect } from 'react';
import { useFeatureVariable, KameleoonException } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { getFeatureVariable, error } = useFeatureVariable();
useEffect(() => {
const featureKey = 'example-feature-key';
const variableKey = 'example-variable-key';
if (error?.type === KameleoonException.FeatureConfigurationNotFound) {
// Handle error
}
const featureVariable = getFeatureVariable(featureKey, variableKey);
}, []);
...
}
useFeatureVariable
returns a callback function getFeatureVariable()
used to obtain feature variables along with an error
object.
Callback Arguments
featureKey: string | number
(required) - unique identifier or key of the feature you want to obtain to a user.variableKey: string
(required) - key of the variable.
Callback Returns
featureVariable: FeatureFlagVariableType
- data associated with this variable for this feature flag
Exceptions Thrown
KameleoonException.FeatureConfigurationNotFound
- Exception indicating that the requested feature ID has not been found in the internal configuration of the SDK. This is usually normal and means that the feature flag has not yet been activated on Kameleoon's side.
Error Handling
An error
object returned from the hook contains message: string
, name: string
and type: KameleoonException
fields. A type
key may be useful for comparing the returned error type against KameleoonException
enum. If there were no errors error
will be null
.
Types
KameleoonError
- an error object type.KameleoonException
- an enum containing all the possibleKameleoonError
types.
withFeatureVariable
import { withFeatureVariable, KameleoonException } from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { getFeatureVariable, featureVariableError } = this.props;
const featureKey = 'example-feature-key';
const variableKey = 'example-variable-key';
if (featureVariableError?.type === KameleoonException.FeatureConfigurationNotFound) {
// Handle error
}
const featureVariable = getFeatureVariable(featureKey, variableKey);
}
...
}
export default withFeatureVariable(MyComponent);
An alternative for useFeatureVariable
hook.
Arguments
Component: React.Component
- component which will be enhanced with the propgetFeatureVariable()
.
Returns
- A wrapped component with additional props as described above.
Error Handling
Unlike useFeatureVariable
hook, which retrieves and error
object, withFeatureVariable
HOC enhances props with named featureVariableError
error to avoid error naming intersection when using several HOCs within compose
.
Track Conversion
A callback function trackConversion()
retrieved via useTrackingConversion
or withTrackingConversion
is used to track conversion. This callback function requires visitorCode
and goalId
to track conversion on this particular goal. In addition, trackConversion()
accepts third optional argument revenue
to track revenue. The visitorCode
is usually identical to the one that was used when triggering the experiment.
trackConversion()
doesn't return any value. And it is non-blocking as the server call is made asynchronously.
useTrackingConversion
import { useEffect } from 'react';
import { useTrackingConversion, useVisitorCode } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { getVisitorCode } = useVisitorCode();
const { trackConversion } = useTrackingConversion();
useEffect(() => {
const visitorCode = getVisitorCode('example.com')
const goalId = 280295;
trackConversion(visitorCode, goalId);
}, []);
...
}
useTrackingConversion
returns a callback function trackConversion()
used for tracking conversion.
Callback Arguments
visitorCode: string
(required) - unique identifier of the user.goalId: number
- (required) key of the variable.revenue: number
(optional) - key of the variable.
Returns
- A callback function
trackConversion()
;
withTrackingConversion
import { withVisitorCode, withTrackingConversion, compose } from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { getVisitorCode, trackConversion } = this.props;
const visitorCode = getVisitorCode('example.com');
const goalId = 230234;
trackConversion(visitorCode, goalId);
}
...
}
export default compose(withVisitorCode, withTrackingConversion)(MyComponent);
An alternative for useTrackingConversion
hook.
Arguments
Component: React.Component
- component which will be enhanced with the proptrackConversion()
.
Returns
- A wrapped component with additional props as described above.
Retrieve Data from Remote Source
An callback function retrieveDataFromRemoteSource()
retrieved via useRetrieveDataFromRemoteSource
or withRetrieveDataFromRemoteSource
can be used to retrieve data using specific key and siteCode from Kameleoon provider. The Data is stored on a remote Kameleoon server. Usually data will be stored on our remote servers via the use of our Data API. This method, along with the availability of our highly scalable servers for this purpose, provides a convenient way to quickly store massive amounts of data that can be later retrieved for each of your visitors / users.
useRetrieveDataFromRemoteSource
import { useEffect, useCallback } from 'react';
import { useRetrieveDataFromRemoteSource, RemoteSourceDataType } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { retrieveDataFromRemoteSource } = useRetrieveDataFromRemoteSource();
const processRetrievedData = useCallback(async () => {
const data: RemoteSourceDataType = await retrieveDataFromRemoteSource('example-key');
// Your code
}, [retrieveDataFromRemoteSource]);
useEffect(() => {
processRetrievedData();
}, [processRetrievedData]);
...
}
useRetrieveDataFromRemoteSource
returns retrieveDataFromRemoteSource()
callback used for obtaining remote data.
Callback Arguments
key: string
(required) - unique key for the current siteCode used to store data on the remote source (can be created viaPOST
request to Kameleoon Data API). This field is mandatory.
Callback Returns
- JSON object with the data posted to Kameleoon Data API.
Returns
- A callback function
retrieveDataFromRemoteSource()
;
Types
RemoteSourceDataType
can be used for handling data type.
withRetrieveDataFromRemoteSource
import { withRetrieveDataFromRemoteSource, RemoteSourceDataType } from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
async componentDidMount() {
const { retrieveDataFromRemoteSource } = this.props;
const data: RemoteSourceDataType = await getVariationAssociatedData('example-key');
// Your code
}
...
}
export default withRetrieveDataFromRemoteSource(MyComponent);
An alternative for useRetrieveDataFromRemoteSource
hook.
Arguments
Component: React.Component
- component which will be enhanced with the propretrieveDataFromRemoteSource()
.
Returns
- A wrapped component with additional props as described above.
Types
RemoteSourceDataType
can be used for handling data type.
Add User Data
A callback function addData()
retrieved via useAddData
or withAddData
is used to add various data to associate with the current user. This callback function requires visitorCode
as a first parameter and then accepts array of various Data Types allowed in Kameleoon.
useAddData
import { useEffect } from 'react';
import { Button } from '@kameleoon/ui';
import {
useAddData,
useBrowser,
useCustomData,
useVisitorCode,
Browser
} from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { getVisitorCode } = useVisitorCode();
const { addData } = useAddData();
const { addBrowser } = useBrowser();
const { addCustomData } = useCustomData();
useEffect(() => {
const visitorCode = getVisitorCode('example.com');
// Single data type passed
addData(visitorCode, addBrowser(Browser.Chrome));
// Several data types passed
addData(visitorCode, addBrowser(Browser.Chrome), addCustomData(1, 'some custom value'));
}, []);
...
}
useAddData
hook returns a callback function addData
used to add client associated data. useAddData
, useBrowser
and useCustomData
shown in code example are used to correctly structure the data.
Callback Arguments
visitorCode: string
(required) - unique identifier of the user.dataTypes: DataInterface[]
(required) - custom data types which may be passed separated by a comma.
withAddData
import {
withAddData,
withBrowser,
withCustomData,
withVisitorCode,
Browser,
compose,
} from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { addData, addBrowser, addCustomData, getVisitorCode } = this.props;
const visitorCode = getVisitorCode('example.com');
// Single data type passed
addData(visitorCode, addBrowser(Browser.Chrome));
// Several data types passed
addData(visitorCode, addBrowser(Browser.Chrome), addCustomData(1, 'some custom value'));
}
...
}
export default compose(
withAddData,
withBrowser,
withCustomData,
withVisitorCode,
)(MyComponent);
An alternative for useAddData
hook.
Arguments
Component: React.Component
- component which will be enhanced with the propaddData()
.
Returns
- A wrapped component with additional props as described above.
Run When Ready
In certain scenarios when working with Kameleoon API it's important to make sure that the client was initialized properly within the certain timeout. It's especially important while using triggerExperiment()
or trackConversion()
. For these cases it's possible to use runWhenReady()
function, retrieved by useRunWhenReady
hook or withRunWhenReady
high-order component.
useRunWhenReady
import { useEffect, useCallback, useState } from 'react';
import { useRunWhenReady, useTriggerExperiment } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { runWhenReady } = useRunWhenReady();
const { getVariationId } = useTriggerExperiment();
const [variationId, setVariationId] = useState<number>(0);
const getVariationSuccessCallback = useCallback(() => {
const id = getVariationId('user_id', 12345);
setVariationId(id);
}, [getVariationId, isRenderProps]);
const getVariationErrorCallback = useCallback(() => {
throw new Error(
"Couldn't get server configuration from HTTP request in a specified time",
);
}, []);
useEffect(() => {
runWhenReady(
getVariationSuccessCallback,
getVariationErrorCallback,
1000,
);
}, [runWhenReady, getVariationSuccessCallback, getVariationErrorCallback]);
...
}
The runWhenReady()
function makes sure that Kameleoon Client will be initialized properly using HTTP call withing the specified timeout.
Callback Arguments
successCallback: () => void
(required) - callback which will be executed on successful client initialization.errorCallback: () => void
(required) - callback which will be executed if client wasn't able to initialize during the timeout.timeout?: number
(optional) - timeout which is given to perform HTTP call for initialization in ms (by default: 2000 ms).
withRunWhenReady
import { useEffect, useCallback, useState } from 'react';
import { withRunWhenReady, withTriggerExperiment } from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
variationSuccessCallback(): void {
const id = this.props.getVariationId('user_id', 12345);
setVariationId(id);
}
variationErrorCallback(): void {
const id = this.props.getVariationId('user_id', 12345);
setVariationId(id);
}
componentDidMount() {
this.props.runWhenReady(this.variationSuccessCallback, this.variationErrorCallback, 1000);
}
...
}
export default compose(
withRunWhenReady,
withTriggerExperiment,
)(MyComponent);
An alternative for useRunWhenReady
hook.
Arguments
Component: React.Component
- component which will be enhanced with the proprunWhenReady()
.
Returns
- A wrapped component with additional props as described above.
Data Flush
Data associated with the current user via addData()
is not immediately sent to the server. It is stored and accumulated until it is sent automatically by the triggerExperiment()
or trackConversion()
, or manually by the flush()
callback function which is retrieve via useFlush
or withFlush
. This allows the developer to control exactly when the data is flushed to servers. For instance, if you call the addData()
a dozen times, it would be a waste of resources to send data to the server after each addData()
invocation. Just call flush()
once at the end.
The flush()
callback function is non-blocking as the server call is made asynchronously.
useFlush
import { useEffect } from 'react';
import { Button } from '@kameleoon/ui';
import {
useAddData,
useBrowser,
useVisitorCode,
useFlush,
Browser
} from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { getVisitorCode } = useVisitorCode();
const { addData } = useAddData();
const { addBrowser } = useBrowser();
const { flush } = useFlush();
useEffect(() => {
const visitorCode = getVisitorCode('example.com');
addData(visitorCode, addBrowser(Browser.Chrome));
flush(visitorCode);
}, []);
...
}
useFlush
return a callback function flush()
. useBrowser
used in the example is used to structure the data correctly.
Callback Arguments
visitorCode: string
(required) - unique identifier of the user.
withFlush
import {
withVisitorCode,
withAddData,
withBrowser,
withFlush,
Browser,
compose,
} from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { addData, addBrowser, flush, getVisitorCode } = this.props;
const visitorCode = getVisitorCode('example.com');
addData(visitorCode, addBrowser(Browser.Chrome));
flush(visitorCode);
}
...
}
export default compose(
withAddData,
withBrowser,
withFlush,
withVisitorCode,
)(MyComponent);
An alternative for useFlush
hook.
Arguments
Component: React.Component
- component which will be enhanced with the propflush()
.
Returns
- A wrapped component with additional props as described above.
Data Structure
The following set of hooks and higher-order components are serving the purpose of structuring the data passed to addData()
function correctly.
useBrowser
import { useEffect } from 'react';
import { useAddData, useBrowser, useVisitorCode, Browser } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { addData } = useAddData();
const { getVisitorCode } = useVisitorCode();
const { addBrowser } = useBrowser();
useEffect(() => {
const visitorCode = getVisitorCode('example.com');
addData(visitorCode, addBrowser(Browser.Chrome));
}, []);
...
}
useBrowser
return a callback function addBrowser()
which add chosen browser to user associated data.
Callback Arguments
browser: Browser
(required) - browser types: CHROME, INTERNET_EXPLORER, FIREFOX, SAFARI, OPERA, OTHER.
Callback Returns
- An instance of
Browser: IBrowser
.
Types
- An interface
IBrowser
describe a returned browser. Browser
enum containing possible browser options.
withBrowser
import {
withVisitorCode,
withAddData,
withBrowser,
Browser,
compose,
} from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { addData, addBrowser, getVisitorCode } = this.props;
const visitorCode = getVisitorCode('example.com');
addData(visitorCode, addBrowser(Browser.Chrome));
}
...
}
export default compose(
withAddData,
withBrowser,
withVisitorCode,
)(MyComponent);
An alternative for useBrowser
hook.
Arguments
Component: React.Component
- component which will be enhanced with the propaddBrowser()
.
Returns
- A wrapped component with additional props as described above.
usePageView
import { useEffect } from 'react';
import { useAddData, usePageView, useVisitorCode } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { addData } = useAddData();
const { getVisitorCode } = useVisitorCode();
const { addPageView } = usePageView();
useEffect(() => {
const visitorCode = getVisitorCode('example.com');
addData(visitorCode, addPageView('example.com', 'title', 3));
}, []);
...
}
usePageView
hook returns a callback function addPageView()
used to structure page view data.
Callback Arguments
url: string
(required) - URL of the page viewed.title: string
(required) - title of the page viewed.referrer: number
(optional) - referrer of the page viewed.
Callback Returns
- An instance of
PageView: IPageView
.
Types
IPageView
an interface describing page view data returned fromaddPageView()
withPageView
import {
withVisitorCode,
withAddData,
withPageView,
compose,
} from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { addData, addPageView, getVisitorCode } = this.props;
const visitorCode = getVisitorCode('example.com');
addData(visitorCode, addPageView('example.com', 'title', 3));
}
...
}
export default compose(
withAddData,
withPageView,
withVisitorCode,
)(MyComponent);
An alternative for usePageView
hook.
Arguments
Component: React.Component
- component which will be enhanced with the propaddPageView()
.
Returns
- A wrapped component with additional props as described above.
useConversion
import { useEffect } from 'react';
import { useAddData, useConversion, useVisitorCode } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { addData } = useAddData();
const { getVisitorCode } = useVisitorCode();
const { addConversion } = useConversion();
useEffect(() => {
const visitorCode = getVisitorCode('example.com');
addData(visitorCode, addConversion(32, 10, false));
}, []);
...
}
useConversion
hook returns a callback function addConversion()
used to structure conversion data.
Callback Arguments
goalId: number
(required) - unique identifier of the goal.revenue: number
(optional) - conversion revenue.negative: boolean
(optional) - defines if the revenue is positive or negative.
Callback Returns
- An instance of
Conversion: IConversion
.
Types
IConversion
interface is used to describe a type ofaddConversion()
returned data.
withConversion
import {
withVisitorCode,
withAddData,
withConversion,
compose,
} from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { addData, addConversion, getVisitorCode } = this.props;
const visitorCode = getVisitorCode('example.com');
addData(visitorCode, addConversion(32, 10, false));
}
...
}
export default compose(
withAddData,
withConversion,
withVisitorCode,
)(MyComponent);
An alternative for useConversion
hook.
Arguments
Component: React.Component
- component which will be enhanced with the propaddConversion()
.
Returns
- A wrapped component with additional props as described above.
useDevice
import { useEffect } from 'react';
import { useAddData, useDevice, useVisitorCode, DeviceType } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { addData } = useAddData();
const { getVisitorCode } = useVisitorCode();
const { addDevice } = useDevice();
useEffect(() => {
const visitorCode = getVisitorCode('example.com');
addData(visitorCode, addDevice(DeviceType.Desktop));
}, []);
...
}
useDevice
hook returns a callback function addDevice()
used to structure device data.
Callback Arguments
device: DeviceType
(required) - device type: Desktop, Phone, Tablet.
Callback Returns
- An instance of
Device: IDevice
.
Types
IDevice
an interface used to describe data returned byaddDevice()
callback.DeviceType
enum containing possible device options.
withDevice
import {
withVisitorCode,
withAddData,
withDevice,
DeviceType,
compose,
} from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { addData, addDevice, getVisitorCode } = this.props;
const visitorCode = getVisitorCode('example.com');
addData(visitorCode, addDevice(DeviceType.Desktop));
}
...
}
export default compose(
withAddData,
withDevice,
withVisitorCode,
)(MyComponent);
An alternative for useDevice
hook.
Arguments
Component: React.Component
- component which will be enhanced with the propaddDevice()
.
Returns
- A wrapped component with additional props as described above.
useCustomData
import { useEffect } from 'react';
import { useAddData, useCustomData, useVisitorCode } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { addData } = useAddData();
const { getVisitorCode } = useVisitorCode();
const { addCustomData } = useCustomData();
useEffect(() => {
const visitorCode = getVisitorCode('example.com');
addData(visitorCode, addCustomData(1, 'some custom value'));
}, []);
...
}
useCustomData
hook returns a callback function addCustomData
used to structure custom data.
Arguments
index: number
(required) - index or unique identifier of the custom data to be stored.value: string
(required) - value of the custom data to be stored.
Returns
- An instance of
CustomData: ICustomData
.
Types
ICustomData
an interface used to describe custom data returned byaddData()
callback.
withCustomData
import {
withVisitorCode,
withAddData,
withCustomData,
compose,
} from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { addData, addCustomData, getVisitorCode } = this.props;
const visitorCode = getVisitorCode('example.com');
addData(visitorCode, addCustomData(1, 'some custom value'));
}
...
}
export default compose(
withAddData,
withCustomData,
withVisitorCode,
)(MyComponent);
An alternative for useAddData
hook.
Arguments
Component: React.Component
- component which will be enhanced with the propaddCustomData()
.
Returns
- A wrapped component with additional props as described above.
Compose
import { withVisitorCode, withTriggerExperiment, compose } from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
componentDidMount() {
const { getVisitorCode, getVariationId } = this.props;
const visitorCode = getVisitorCode('example.com');
const experimentId = 230243;
const variationId = getVariationId(visitorCode, experimentId);
}
...
}
export default compose(withVisitorCode, withTriggerExperiment)(MyComponent);
compose()
is a helper higher-order component used for easier composition.
Arguments
HOCs
- high order components to be composed.
Returns
- A function obtained by composing the argument HOCs, which is used as single high order component wrapper.
Technical Considerations
Kameleoon made an important architectural design decision with its SDK technology, namely that every SDK must comply with a zero latency policy. In practice, this means that any blocking remote server call should be banned, as even the fastest remote call would add a 20ms latency to your application. And if for any reason our servers are slower to reply than usual (unfortunately, this can happen), this delay can quickly increase to hundreds of milliseconds, seconds... or even completely block the run of your web-application for the end user. We believe that web performance is of paramount importance in today's world and we don't think adding A/B testing or feature flagging capabilities should come at the cost of a slow down in your web-application.
However, in the case of the React SDK, since it runs on users' devices, the configuration of all active experiments / feature flags has to be fetched at the start of the session. It cannot be fetched once for every , similarly to the server-side case. This introduces a mandatory distant server call with an associated callback, which means code using the React SDK (implementing experiments or feature flags) cannot be ran prior to the execution of this callback. For maximal performance, this can be avoided by using our Activation API
in tandem with a standard Kameleoon install, where the configuration data is directly embedded in the Kameleoon application file (i.e. the JavaScript file contains both the engine code and the configuration of active experiments). But this is a completely different process (advantages of each method are highlighted here), with a different API and no npm package (installation is done by integrating a standard JS tag on the HTML source page). It is described on this article.
Apart from this initial remote call, we guarantee that the use of our SDKs has absolutely no performance impact. Variation allocation for experiments takes place directly on the SDK code (without any distant API call), and tracking calls are made asynchronously in a non-blocking way (in the background).
Having a zero latency policy also imposes some other constraints. The main one is that user data about your visitor should be kept locally, and not fetched from a remote server. For instance, if you set a custom data for a given visitor, we must store this somehow in the user's device. In the case of the React SDK, this is implemented via a map of visitor data directly on the browser LocalStorage. So if you use addCustomData and then addData methods, the information will be stored in the browser's LocalStorage. It should usually not grow too big in size, unless you use an extremely large amount of custom data.
Overview
When you update your experiment or feature flag configuration, the SDK can get it in two different ways. The first - polling - consists in retrieving the configuration at regular intervals. The second - streaming - is to retrieve the new configuration immediately. The way it's done can be changed in the Administration section on Kameleoon Back-Office.
Polling
This mode of obtaining the configuration is used by default. The SDK will send a request to Cloudflare CDN at regular intervals to retrieve the configuration. If you have not set an interval in the SDK configuration, the configuration in SDK will be refreshed every 60 minutes. It can be configured with actions_configuration_refresh_interval parameter.
-
Benefits:
- When intervals are moderately spaced, this way of updating configuration consumes nominal memory and network resources.
Streaming
This mode allows the SDK to automatically take into account the new configuration without delay. When turned on, Kameleoon SDK is notified of any changes to the configuration in real-time, thanks to server-sent events (SSE).
-
Benefits:
- Makes it possible to propagate and apply a new configuration in real-time.
- Reduce network traffic compared to polling at short intervals, as streaming does not require sending periodic requests. It opens the connection once and then keeps it permanently open and ready to receive data.
If you rely on instant data updates (real-time), then streaming is for you. If you wish to activate this mode, please contact us.
React Native Considerations
Visitor Code Generation
React Native uses AsyncStorage
to store feature flag data so getVisitorCode callback retrieved from useVisitorCode
hook won't be able to obtain visitor code safely, instead there are dedicated getAsyncVisitorCode callback that will retrieve visitor code asynchronously. The following hook and HOC are meant for retrieving the concerning callback.
useAsyncVisitorCode
import { useState } from 'react';
import { uuidv4 } from 'uuid';
import { useAsyncVisitorCode } from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const { getAsyncVisitorCode } = useAsyncVisitorCode();
const [visitorCode, setVisitorCode] = useState<string>('');
async function retrieveVisitorCode(): Promise<void> {
// Without defaultVisitorCode argument
const result = await getAsyncVisitorCode('example.com');
// With defaultVisitorCode argument
const result = await getAsyncVisitorCode('example.com', uuidv4());
setVisitorCode(result);
}
...
}
useAsyncVisitorCode
returns a callback function getAsyncVisitorCode()
used to obtain visitor code asynchronously.
Callback Arguments
topLevelDomain: string
(required) - current top level domain for the concerned site (this information is needed to set the corresponding cookie accordingly, on the top level domain).defaultVisitorCode: string
(optional) - This parameter will be used as thevisitorCode
if no existingkameleoonVisitorCode
cookie is found on the request. This field is optional, and by default a randomvisitorCode
will be generated.
Callback Returns
visitorCode: string
- a visitorCode that will be associated with this particular user and should be used with most of the methods of the SDK.
withAsyncVisitorCode
import { uuidv4 } from 'uuid';
import { withAsyncVisitorCode } from '@kameleoon/react-sdk';
class MyComponent extends React.Component {
async componentDidMount(): Promise<void> {
const { getAsyncVisitorCode } = this.props;
// Without defaultVisitorCode argument
const visitorCode = await getAsyncVisitorCode('example.com');
// With defaultVisitorCode argument
const visitorCode = await getAsyncVisitorCode('example.com', uuidv4());
}
...
}
export default withVisitorCode(MyComponent);
An alternative for useAsyncVisitorCode
hook.
Arguments
Component: React.Component
- component which will be enhanced with the propgetAsyncVisitorCode()
.
Returns
- A wrapped component with additional props as described above.
Common Methods Usage
import { useState, useEffect } from 'react';
import {
useActivateFeature,
useRunWhenReady,
useAsyncVisitorCode,
} from '@kameleoon/react-sdk';
function MyComponent(): JSX.Element {
const featureKey = 'example-feature-key';
const [visitorCode, setVisitorCode] = useState<string>('');
const { getAsyncVisitorCode } = useAsyncVisitorCode();
async function updateVisitorCode(): Promise<void> {
const result = await getAsyncVisitorCode('example.com');
setVisitorCode(result);
}
useEffect(() => {
updateVisitorCode();
}, [updateVisitorCode]);
useEffect(() => {
runWhenReady(
() => {
setIsFeature(hasFeature(featureKey, visitorCode));
},
() => {},
);
}, [hasFeature, visitorCode, setIsFeature]);
}
For the same reason of using AsyncStorage
it is preferable to use all the other sdk methods by wrapping their callback calls in runWhenReady function, which will set a timeout making sure that all the asynchronous data flow will be processed correctly.
The code example demonstrate the best way to utilize useActivateFeature callback for React Native application. All the other callbacks can be handled in the similar fashion.