{"id":19935064,"url":"https://github.com/optimizely/react-sdk","last_synced_at":"2025-04-05T01:05:00.827Z","repository":{"id":35136227,"uuid":"211112543","full_name":"optimizely/react-sdk","owner":"optimizely","description":"React SDK for Optimizely Feature Experimentation and Optimizely Full Stack (legacy)","archived":false,"fork":false,"pushed_at":"2024-05-22T16:08:50.000Z","size":1263,"stargazers_count":87,"open_issues_count":24,"forks_count":33,"subscribers_count":61,"default_branch":"master","last_synced_at":"2024-05-22T16:13:40.098Z","etag":null,"topics":["optimizely-environment-prod","optimizely-environment-public","optimizely-owner-px"],"latest_commit_sha":null,"homepage":"https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/javascript-react-sdk","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/optimizely.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-26T14:43:14.000Z","updated_at":"2024-06-18T13:55:05.916Z","dependencies_parsed_at":"2023-11-07T00:19:42.337Z","dependency_job_id":"5c03f080-41fd-4518-89fb-88add867ae30","html_url":"https://github.com/optimizely/react-sdk","commit_stats":{"total_commits":102,"total_committers":18,"mean_commits":5.666666666666667,"dds":0.7450980392156863,"last_synced_commit":"6dfbc1caf988dd2e21479cfb12edf1b397b9d42d"},"previous_names":[],"tags_count":37,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/optimizely%2Freact-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/optimizely%2Freact-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/optimizely%2Freact-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/optimizely%2Freact-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/optimizely","download_url":"https://codeload.github.com/optimizely/react-sdk/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247271518,"owners_count":20911587,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["optimizely-environment-prod","optimizely-environment-public","optimizely-owner-px"],"created_at":"2024-11-12T23:18:40.079Z","updated_at":"2025-04-05T01:05:00.808Z","avatar_url":"https://github.com/optimizely.png","language":"TypeScript","readme":"# Optimizely React SDK\r\n\r\nThis repository houses the React SDK for use with Optimizely Feature Experimentation and Optimizely Full Stack (legacy).\r\n\r\nOptimizely Feature Experimentation is an A/B testing and feature management tool for product development teams that enables you to experiment at every step. Using Optimizely Feature Experimentation allows for every feature on your roadmap to be an opportunity to discover hidden insights. Learn more at [Optimizely.com](https://www.optimizely.com/products/experiment/feature-experimentation/), or see the [developer documentation](https://docs.developers.optimizely.com/feature-experimentation/docs/introduction).\r\n\r\nOptimizely Rollouts is [free feature flags](https://www.optimizely.com/free-feature-flagging/) for development teams. You can easily roll out and roll back features in any application without code deploys, mitigating risk for every feature on your roadmap.\r\n\r\n## Get Started\r\n\r\nRefer to the [React SDK's developer documentation](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/javascript-react-sdk) for detailed instructions on getting started with using the SDK.\r\n\r\nFor React Native, review the [React Native developer documentation](https://docs.developers.optimizely.com/feature-experimentation/docs/javascript-react-native-sdk).\r\n\r\n\r\n### Features\r\n\r\n- Automatic datafile downloading\r\n- User ID + attributes memoization\r\n- Render blocking until datafile is ready via a React API\r\n- Optimizely timeout (only block rendering up to the number of milliseconds you specify)\r\n- Library of React components and hooks to use with [feature flags](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/create-feature-flags)\r\n\r\n### Compatibility\r\n\r\nThe React SDK is compatible with `React 16.8.0 +`\r\n\r\n### Example\r\n\r\n```jsx\r\nimport {\r\n  createInstance,\r\n  OptimizelyProvider,\r\n  useDecision,\r\n} from '@optimizely/react-sdk';\r\n\r\nconst optimizelyClient = createInstance({\r\n  sdkKey: 'your-optimizely-sdk-key',\r\n});\r\n\r\nfunction MyComponent() {\r\n  const [decision] = useDecision('sort-algorithm');\r\n  return (\r\n    \u003cReact.Fragment\u003e\r\n      \u003cSearchComponent algorithm={decision.variables.algorithm} /\u003e\r\n      { decision.variationKey === 'relevant_first' \u0026\u0026 \u003cRelevantFirstList /\u003e }\r\n      { decision.variationKey === 'recent_first' \u0026\u0026 \u003cRecentFirstList /\u003e }\r\n    \u003c/React.Fragment\u003e\r\n  );\r\n}\r\n\r\nclass App extends React.Component {\r\n  render() {\r\n    return (\r\n      \u003cOptimizelyProvider\r\n        optimizely={optimizelyClient}\r\n        timeout={500}\r\n        user={{ id: window.userId, attributes: { plan_type: 'bronze' } }}\r\n      \u003e\r\n        \u003cMyComponent /\u003e\r\n      \u003c/OptimizelyProvider\u003e\r\n    );\r\n  }\r\n}\r\n```\r\n\r\n### Install the SDK\r\n\r\n```\r\nnpm install @optimizely/react-sdk\r\n```\r\n\r\nFor **React Native**, installation instruction is bit different. Check out the \r\n- [Official Installation guide](https://docs.developers.optimizely.com/feature-experimentation/docs/install-sdk-reactnative)\r\n- [Expo React Native Sample App](https://github.com/optimizely/expo-react-native-sdk-sample)\r\n\r\n## Use the React SDK\r\n\r\n### Initialization\r\n\r\n## `createInstance`\r\n\r\nThe `ReactSDKClient` client created via `createInstance` is the programmatic API to evaluating features and experiments and tracking events. The `ReactSDKClient` is what powers the rest of the ReactSDK internally.\r\n\r\n_arguments_\r\n\r\n- `config : object` Object with SDK configuration parameters. This has the same format as the object passed to the `createInstance` method of the core `@optimizely/javascript-sdk` module. For details on this object, see the following pages from the developer docs:\r\n  - [Instantiate](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/initialize-sdk-react)\r\n  - [JavaScript: Client-side Datafile Management](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/javascript-client-side-implementation)\r\n\r\n_returns_\r\n\r\n- A `ReactSDKClient` instance.\r\n\r\n```jsx\r\nimport { OptimizelyProvider, createInstance } from '@optimizely/react-sdk';\r\n\r\nconst optimizely = createInstance({\r\n  datafile: window.optimizelyDatafile,\r\n});\r\n```\r\n\r\n## `\u003cOptimizelyProvider\u003e`\r\n\r\nRequired at the root level. Leverages React’s `Context` API to allow access to the `ReactSDKClient` to the `useDecision` hook.\r\n\r\n_props_\r\n\r\n- `optimizely : ReactSDKClient` created from `createInstance`\r\n- `user: { id: string; attributes?: { [key: string]: any } } | Promise` User info object - `id` and `attributes` will be passed to the SDK for every feature flag, A/B test, or `track` call, or a `Promise` for the same kind of object\r\n- `timeout : Number` (optional) The amount of time for `useDecision` to return `null` flag Decision while waiting for the SDK instance to become ready, before resolving.\r\n- `isServerSide : Boolean` (optional) must pass `true` here for server side rendering\r\n- `userId : String` (optional) **_Deprecated, prefer using `user` instead_**. Another way to provide user id. The `user` object prop takes precedence when both are provided.\r\n- `userAttributes : Object` : (optional) **_Deprecated, prefer using `user` instead_**. Another way to provide user attributes. The `user` object prop takes precedence when both are provided.\r\n\r\n### Readiness\r\n\r\nBefore rendering real content, both the datafile and the user must be available to the SDK.\r\n\r\n#### Load the datafile synchronously\r\n\r\nSynchronous loading is the preferred method to ensure that Optimizely is always ready and doesn't add any delay or asynchronous complexity to your application. When initializing with both the SDK key and datafile, the SDK will use the given datafile to start, then download the latest version of the datafile in the background.\r\n\r\n```jsx\r\nimport { OptimizelyProvider, createInstance } from '@optimizely/react-sdk';\r\n\r\nconst optimizelyClient = createInstance({\r\n  datafile: window.optimizelyDatafile,\r\n  sdkKey: 'your-optimizely-sdk-key', // Optimizely environment key\r\n});\r\n\r\nclass AppWrapper extends React.Component {\r\n  render() {\r\n    return (\r\n      \u003cOptimizelyProvider optimizely={optimizelyClient} user={{ id: window.userId }}\u003e\r\n        \u003cApp /\u003e\r\n      \u003c/OptimizelyProvider\u003e\r\n    );\r\n  }\r\n}\r\n```\r\n\r\n#### Load the datafile asynchronously\r\n\r\nIf you don't have the datafile downloaded, the `ReactSDKClient` can fetch the datafile for you. However, instead of waiting for the datafile to fetch before you render your app, you can immediately render your app and provide a `timeout` option to `\u003cOptimizelyProvider optimizely={optimizely} timeout={200}\u003e`. The `useDecision` hook returns `isClientReady` and `didTimeout`. You can use these to block rendering of component until the datafile loads or the timeout is over.\r\n\r\n```jsx\r\nimport { OptimizelyProvider, createInstance, useDecision } from '@optimizely/react-sdk';\r\n\r\nconst optimizelyClient = createInstance({\r\n  sdkKey: 'your-optimizely-sdk-key', // Optimizely environment key\r\n});\r\n\r\nfunction MyComponent() {\r\n  const [decision, isClientReady, didTimeout] = useDecision('the-flag');\r\n  return (\r\n    \u003cReact.Fragment\u003e\r\n      { isClientReady \u0026\u0026 \u003cdiv\u003eThe Component\u003c/div\u003e }\r\n      { didTimeout \u0026\u0026 \u003cdiv\u003eDefault Component\u003c/div\u003e}\r\n      { /* If client is not ready and time out has not occured yet, do not render anything */ }\r\n    \u003c/React.Fragment\u003e\r\n  );\r\n}\r\n\r\nclass App extends React.Component {\r\n  render() {\r\n    return (\r\n      \u003cOptimizelyProvider\r\n        optimizely={optimizelyClient}\r\n        timeout={500}\r\n        user={{ id: window.userId, attributes: { plan_type: 'bronze' } }}\r\n      \u003e\r\n        \u003cMyComponent /\u003e\r\n      \u003c/OptimizelyProvider\u003e\r\n    );\r\n  }\r\n}\r\n```\r\n\r\n#### Set user asynchronously\r\n\r\nIf user information is synchronously available, it can be provided as the `user` object prop, as in prior examples. But, if user information must be fetched asynchronously, the `user` prop can be a `Promise` for a `user` object with the same properties (`id` and `attributes`):\r\n\r\n```jsx\r\nimport { OptimizelyProvider, createInstance } from '@optimizely/react-sdk';\r\nimport { fetchUser } from './user';\r\n\r\nconst optimizely = createInstance({\r\n  datafile: window.optimizelyDatafile,\r\n});\r\n\r\nconst userPromise = fetchUser(); // fetchUser returns a Promise for an object with { id, attributes }\r\n\r\nclass AppWrapper extends React.Component {\r\n  render() {\r\n    return (\r\n      \u003cOptimizelyProvider optimizely={optimizely} user={userPromise}\u003e\r\n        \u003cApp /\u003e\r\n      \u003c/OptimizelyProvider\u003e\r\n    );\r\n  }\r\n}\r\n```\r\n\r\n## `useDecision` Hook\r\n\r\nA [React Hook](https://react.dev/learn/state-a-components-memory#meet-your-first-hook) to retrieve the decision result for a flag key, optionally auto updating that decision based on underlying user or datafile changes.\r\n\r\n_arguments_\r\n\r\n- `flagKey : string` The key of the feature flag.\r\n- `options : Object`\r\n  - `autoUpdate : boolean` (optional) If true, this hook will update the flag decision in response to datafile or user changes. Default: `false`.\r\n  - `timeout : number` (optional) Client timeout as described in the `OptimizelyProvider` section. Overrides any timeout set on the ancestor `OptimizelyProvider`.\r\n  - `decideOption: OptimizelyDecideOption[]` (optional) Array of OptimizelyDecideOption enums.\r\n- `overrides : Object`\r\n  - `overrideUserId : string` (optional) Override the userId to be used to obtain the decision result for this hook.\r\n  - `overrideAttributes : optimizely.UserAttributes` (optional) Override the user attributes to be used to obtain the decision result for this hook.\r\n\r\n_returns_\r\n\r\n- `Array` of:\r\n\r\n  - `decision : OptimizelyDecision` - Decision result for the flag key.\r\n  - `clientReady : boolean` - Whether or not the underlying `ReactSDKClient` instance is ready or not.\r\n  - `didTimeout : boolean` - Whether or not the underlying `ReactSDKClient` became ready within the allowed `timeout` range.\r\n\r\n  _Note: `clientReady` can be true even if `didTimeout` is also true. This indicates that the client became ready *after* the timeout period._\r\n\r\n### Render something if flag is enabled\r\n\r\n```jsx\r\nimport { useEffect } from 'react';\r\nimport { useDecision } from '@optimizely/react-sdk';\r\n\r\nfunction LoginComponent() {\r\n  const [decision, clientReady] = useDecision(\r\n    'login-flag',\r\n    { autoUpdate: true },\r\n    {\r\n      /* (Optional) User overrides */\r\n    }\r\n  );\r\n  useEffect(() =\u003e {\r\n    document.title = decision.enabled ? 'login-new' : 'login-default';\r\n  }, [decision.enabled]);\r\n\r\n  return (\r\n    \u003cp\u003e\r\n      \u003ca href={decision.enabled ? '/login-new' : '/login-default'}\u003eClick to login\u003c/a\u003e\r\n    \u003c/p\u003e\r\n  );\r\n}\r\n```\r\n\r\n## `withOptimizely`\r\n\r\nAny component under the `\u003cOptimizelyProvider\u003e` can access the Optimizely `ReactSDKClient` via the higher-order component (HoC) `withOptimizely`.\r\n\r\n_arguments_\r\n\r\n- `Component : React.Component` Component which will be enhanced with the following props:\r\n  - `optimizely : ReactSDKClient` The client object which was passed to the `OptimizelyProvider`\r\n  - `optimizelyReadyTimeout : number | undefined` The timeout which was passed to the `OptimizelyProvider`\r\n  - `isServerSide : boolean` Value that was passed to the `OptimizelyProvider`\r\n\r\n_returns_\r\n\r\n- A wrapped component with additional props as described above\r\n\r\n### Example\r\n\r\n```jsx\r\nimport { withOptimizely } from '@optimizely/react-sdk';\r\n\r\nclass MyComp extends React.Component {\r\n  constructor(props) {\r\n    super(props);\r\n    const { optimizely } = this.props;\r\n    const decision = optimizely.decide('feat1');    \r\n\r\n    this.state = {\r\n      decision.enabled,\r\n      decision.variables,\r\n    };\r\n  }\r\n\r\n  render() {}\r\n}\r\n\r\nconst WrappedMyComponent = withOptimizely(MyComp);\r\n```\r\n\r\n**_Note:_** The `optimizely` client object provided via `withOptimizely` is automatically associated with the `user` prop passed to the ancestor `OptimizelyProvider` - the `id` and `attributes` from that `user` object will be automatically forwarded to all appropriate SDK method calls. So, there is no need to pass the `userId` or `attributes` arguments when calling methods of the `optimizely` client object, unless you wish to use _different_ `userId` or `attributes` than those given to `OptimizelyProvider`.\r\n\r\n## `useContext`\r\n\r\nAny component under the `\u003cOptimizelyProvider\u003e` can access the Optimizely `ReactSDKClient` via the `OptimizelyContext` with `useContext`.\r\n\r\n_arguments_\r\n- `OptimizelyContext : React.Context\u003cOptimizelyContextInterface\u003e` The Optimizely context initialized in a parent component (or App).\r\n\r\n_returns_\r\n- Wrapped object:\r\n  - `optimizely : ReactSDKClient` The client object which was passed to the `OptimizelyProvider`\r\n  - `isServerSide : boolean` Value that was passed to the `OptimizelyProvider`\r\n  - `timeout : number | undefined` The timeout which was passed to the `OptimizelyProvider`\r\n\r\n### Example\r\n\r\n```jsx\r\nimport React, { useContext } from 'react';\r\nimport { OptimizelyContext } from '@optimizely/react-sdk';\r\n\r\nfunction MyComponent() {\r\n  const { optimizely, isServerSide, timeout } = useContext(OptimizelyContext);\r\n  const decision = optimizely.decide('my-feature');\r\n  const onClick = () =\u003e {\r\n    optimizely.track('signup-clicked');\r\n    // rest of your click handling code\r\n  };\r\n  return (\r\n    \u003c\u003e\r\n      { decision.enabled \u0026\u0026 \u003cp\u003eMy feature is enabled\u003c/p\u003e }\r\n      { !decision.enabled \u0026\u0026 \u003cp\u003eMy feature is disabled\u003c/p\u003e }\r\n      { decision.variationKey === 'control-variation' \u0026\u0026 \u003cp\u003eCurrent Variation\u003c/p\u003e }\r\n      { decision.variationKey === 'experimental-variation' \u0026\u0026 \u003cp\u003eBetter Variation\u003c/p\u003e }\r\n      \u003cbutton onClick={onClick}\u003eSign Up!\u003c/button\u003e\r\n    \u003c/\u003e\r\n  );\r\n}\r\n```\r\n\r\n### Tracking\r\nUse the built-in `useTrackEvent` hook to access the `track` method of optimizely instance\r\n\r\n```jsx\r\nimport { useTrackEvent } from '@optimizely/react-sdk';\r\n\r\nfunction SignupButton() {\r\n  const [track, clientReady, didTimeout] = useTrackEvent()\r\n\r\n  const handleClick = () =\u003e {\r\n    if(clientReady) {\r\n      track('signup-clicked')\r\n    }\r\n  }\r\n\r\n  return (\r\n    \u003cbutton onClick={handleClick}\u003eSignup\u003c/button\u003e\r\n  )\r\n}\r\n```\r\n\r\nOr you can use the `withOptimizely` HoC.\r\n\r\n```jsx\r\nimport { withOptimizely } from '@optimizely/react-sdk';\r\n\r\nclass SignupButton extends React.Component {\r\n  onClick = () =\u003e {\r\n    const { optimizely } = this.props;\r\n    optimizely.track('signup-clicked');\r\n    // rest of click handler\r\n  };\r\n\r\n  render() {\r\n    \u003cbutton onClick={this.onClick}\u003eSignup\u003c/button\u003e;\r\n  }\r\n}\r\n\r\nconst WrappedSignupButton = withOptimizely(SignupButton);\r\n```\r\n\r\n**_Note:_** As mentioned above, the `optimizely` client object provided via `withOptimizely` is automatically associated with the `user` prop passed to the ancestor `OptimizelyProvider.` There is no need to pass `userId` or `attributes` arguments when calling `track`, unless you wish to use _different_ `userId` or `attributes` than those given to `OptimizelyProvider`.\r\n\r\n## `ReactSDKClient`\r\n\r\nThe following type definitions are used in the `ReactSDKClient` interface:\r\n\r\n- `UserAttributes : { [name: string]: any }`\r\n- `User : { id: string | null, attributes: userAttributes }`\r\n- `VariableValuesObject : { [key: string]: any }`\r\n- `EventTags : { [key: string]: string | number | boolean; }`\r\n\r\n`ReactSDKClient` instances have the methods/properties listed below. Note that in general, the API largely matches that of the core `@optimizely/optimizely-sdk` client instance, which is documented on the [Optimizely Feature Experimentation developer docs site](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/welcome). The major exception is that, for most methods, user id \u0026 attributes are **_optional_** arguments. `ReactSDKClient` has a current user. This user's id \u0026 attributes are automatically applied to all method calls, and overrides can be provided as arguments to these method calls if desired.\r\n\r\n- `onReady(opts?: { timeout?: number }): Promise\u003conReadyResult\u003e` Returns a Promise that fulfills with an `onReadyResult` object representing the initialization process. The instance is ready when it has fetched a datafile and a user is available (via `setUser` being called with an object, or a Promise passed to `setUser` becoming fulfilled). If the `timeout` period happens before the client instance is ready, the `onReadyResult` object will contain an additional key, `dataReadyPromise`, which can be used to determine when, if ever, the instance does become ready.\r\n- `user: User` The current user associated with this client instance\r\n- `setUser(userInfo: User | Promise\u003cUser\u003e): void` Call this to update the current user\r\n- `onUserUpdate(handler: (userInfo: User) =\u003e void): () =\u003e void` Subscribe a callback to be called when this instance's current user changes. Returns a function that will unsubscribe the callback.\r\n- `decide(key: string, options?: optimizely.OptimizelyDecideOption[], overrideUserId?: string, overrideAttributes?: optimizely.UserAttributes): OptimizelyDecision` Returns a decision result for a flag key for a user. The decision result is returned in an OptimizelyDecision object, and contains all data required to deliver the flag rule.\r\n- `decideAll(options?: optimizely.OptimizelyDecideOption[], overrideUserId?: string, overrideAttributes?: optimizely.UserAttributes): { [key: string]: OptimizelyDecision }` Returns decisions for all active (unarchived) flags for a user.\r\n- `decideForKeys(keys: string[], options?: optimizely.OptimizelyDecideOption[], overrideUserId?: string, overrideAttributes?: optimizely.UserAttributes): { [key: string]: OptimizelyDecision }` Returns an object of decision results mapped by flag keys.\r\n- `activate(experimentKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): string | null` Activate an experiment, and return the variation for the given user.\r\n- `getVariation(experimentKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): string | null` Return the variation for the given experiment and user.\r\n- `getFeatureVariables(featureKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): VariableValuesObject`: Decide and return variable values for the given feature and user \u003cbr /\u003e \u003cb\u003eWarning:\u003c/b\u003e Deprecated since 2.1.0 \u003cbr /\u003e `getAllFeatureVariables` is added in JavaScript SDK which is similarly returning all the feature variables, but it sends only single notification of type `all-feature-variables` instead of sending for each variable. As `getFeatureVariables` was added when this functionality wasn't provided by `JavaScript SDK`, so there is no need of it now and it would be removed in next major release\r\n- `getFeatureVariableString(featureKey: string, variableKey: string, overrideUserId?: string, overrideAttributes?: optimizely.UserAttributes): string | null`: Decide and return the variable value for the given feature, variable, and user\r\n- `getFeatureVariableInteger(featureKey: string, variableKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): number | null` Decide and return the variable value for the given feature, variable, and user\r\n- `getFeatureVariableBoolean(featureKey: string, variableKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): boolean | null` Decide and return the variable value for the given feature, variable, and user\r\n- `getFeatureVariableDouble(featureKey: string, variableKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): number | null` Decide and return the variable value for the given feature, variable, and user\r\n- `isFeatureEnabled(featureKey: string, overrideUserId?: string, overrideAttributes?: UserAttributes): boolean` Return the enabled status for the given feature and user\r\n- `getEnabledFeatures(overrideUserId?: string, overrideAttributes?: UserAttributes): Array\u003cstring\u003e`: Return the keys of all features enabled for the given user\r\n- `track(eventKey: string, overrideUserId?: string | EventTags, overrideAttributes?: UserAttributes, eventTags?: EventTags): void` Track an event to the Optimizely results backend\r\n- `setForcedVariation(experiment: string, overrideUserIdOrVariationKey: string, variationKey?: string | null): boolean` Set a forced variation for the given experiment, variation, and user. **Note**: calling `setForcedVariation` on a given client will trigger a re-render of all `useExperiment` hooks and `OptimizelyExperiment` components that are using that client.\r\n- `getForcedVariation(experiment: string, overrideUserId?: string): string | null` Get the forced variation for the given experiment, variation, and user\r\n\r\n## Rollout or experiment a feature user-by-user\r\n\r\nTo rollout or experiment on a feature by user rather than by random percentage, you will use Attributes and Audiences. To do this, follow the documentation on how to [run a beta](https://docs.developers.optimizely.com/feature-experimentation/docs/run-a-beta) using the React code samples.\r\n\r\n## Server Side Rendering\r\n\r\nRight now server side rendering is possible with a few caveats.\r\n\r\n**Caveats**\r\n\r\n1. You must download the datafile manually and pass in via the `datafile` option. Can not use `sdkKey` to automatically download.\r\n\r\n2. Rendering of components must be completely synchronous (this is true for all server side rendering), thus the Optimizely SDK assumes that the optimizely client has been instantiated and fired it's `onReady` event already.\r\n\r\n### Setting up `\u003cOptimizelyProvider\u003e`\r\n\r\nSimilar to browser side rendering you will need to wrap your app (or portion of the app using Optimizely) in the `\u003cOptimizelyProvider\u003e` component. A new prop\r\n`isServerSide` must be equal to true.\r\n\r\n```jsx\r\n\u003cOptimizelyProvider optimizely={optimizely} user={{ id: 'user1' }} isServerSide={true}\u003e\r\n  \u003cApp /\u003e\r\n\u003c/OptimizelyProvider\u003e\r\n```\r\n\r\nAll other Optimizely components, such as `\u003cOptimizelyFeature\u003e` and `\u003cOptimizelyExperiment\u003e` can remain the same.\r\n\r\n### Full example\r\n\r\n```jsx\r\nimport * as React from 'react';\r\nimport * as ReactDOMServer from 'react-dom/server';\r\n\r\nimport {\r\n  createInstance,\r\n  OptimizelyProvider,\r\n  useDecision,\r\n} from '@optimizely/react-sdk';\r\n\r\nconst fetch = require('node-fetch');\r\n\r\nfunction MyComponent() {\r\n  const [decision] = useDecision('flag1');\r\n  return (\r\n    \u003cReact.Fragment\u003e\r\n      { decision.enabled \u0026\u0026 \u003cp\u003eThe feature is enabled\u003c/p\u003e }\r\n      { !decision.enabled \u0026\u0026 \u003cp\u003eThe feature is not enabled\u003c/p\u003e }\r\n      { decision.variationKey === 'variation1' \u0026\u0026 \u003cp\u003eVariation 1\u003c/p\u003e }\r\n      { decision.variationKey === 'variation2' \u0026\u0026 \u003cp\u003eVariation 2\u003c/p\u003e }\r\n    \u003c/React.Fragment\u003e\r\n  );\r\n}\r\n\r\nasync function main() {\r\n  const resp = await fetch('https://cdn.optimizely.com/datafiles/\u003cYour-SDK-Key\u003e.json');\r\n  const datafile = await resp.json();\r\n  const optimizelyClient = createInstance({\r\n    datafile,\r\n  });\r\n\r\n  const output = ReactDOMServer.renderToString(\r\n    \u003cOptimizelyProvider optimizely={optimizelyClient} user={{ id: 'user1' }} isServerSide={true}\u003e\r\n      \u003cMyComponent /\u003e\r\n    \u003c/OptimizelyProvider\u003e\r\n  );\r\n  console.log('output', output);\r\n}\r\nmain();\r\n```\r\n\r\n## Disabled event dispatcher\r\n\r\nTo disable sending all events to Optimizely's results backend, use the `logOnlyEventDispatcher` when creating a client:\r\n\r\n```js\r\nimport { createInstance, logOnlyEventDispatcher } from '@optimizely/react-sdk';\r\n\r\nconst optimizely = createInstance({\r\n  datafile: window.optimizelyDatafile,\r\n  eventDispatcher: logOnlyEventDispatcher,\r\n});\r\n```\r\n\r\n### Additional code\r\n\r\nThis repository includes the following third party open source code:\r\n\r\n[**hoist-non-react-statics**](https://github.com/mridgway/hoist-non-react-statics)\r\nCopyright \u0026copy; 2015 Yahoo!, Inc.\r\nLicense: [BSD](https://github.com/mridgway/hoist-non-react-statics/blob/master/LICENSE.md)\r\n\r\n[**js-tokens**](https://github.com/lydell/js-tokens)\r\nCopyright \u0026copy; 2014, 2015, 2016, 2017, 2018, 2019 Simon Lydell\r\nLicense: [MIT](https://github.com/lydell/js-tokens/blob/master/LICENSE)\r\n\r\n[**json-schema**](https://github.com/kriszyp/json-schema)\r\nCopyright \u0026copy; 2005-2015, The Dojo Foundation\r\nLicense: [BSD](https://github.com/kriszyp/json-schema/blob/master/LICENSE)\r\n\r\n[**lodash**](https://github.com/lodash/lodash/)\r\nCopyright \u0026copy; JS Foundation and other contributors\r\nLicense: [MIT](https://github.com/lodash/lodash/blob/master/LICENSE)\r\n\r\n[**loose-envify**](https://github.com/zertosh/loose-envify)\r\nCopyright \u0026copy; 2015 Andres Suarez \u003czertosh@gmail.com\u003e\r\nLicense: [MIT](https://github.com/zertosh/loose-envify/blob/master/LICENSE)\r\n\r\n[**node-murmurhash**](https://github.com/perezd/node-murmurhash)\r\nCopyright \u0026copy; 2012 Gary Court, Derek Perez\r\nLicense: [MIT](https://github.com/perezd/node-murmurhash/blob/master/README.md)\r\n\r\n[**object-assign**](https://github.com/sindresorhus/object-assign)\r\nCopyright \u0026copy; Sindre Sorhus (sindresorhus.com)\r\nLicense: [MIT](https://github.com/sindresorhus/object-assign/blob/master/license)\r\n\r\n[**promise-polyfill**](https://github.com/taylorhakes/promise-polyfill)\r\nCopyright \u0026copy; 2014 Taylor Hakes\r\nCopyright \u0026copy; 2014 Forbes Lindesay\r\nLicense: [MIT](https://github.com/taylorhakes/promise-polyfill/blob/master/LICENSE)\r\n\r\n[**react-is**](https://github.com/facebook/react)\r\nCopyright \u0026copy; Facebook, Inc. and its affiliates.\r\nLicense: [MIT](https://github.com/facebook/react/blob/master/LICENSE)\r\n\r\n[**react**](https://github.com/facebook/react)\r\nCopyright \u0026copy; Facebook, Inc. and its affiliates.\r\nLicense: [MIT](https://github.com/facebook/react/blob/master/LICENSE)\r\n\r\n[**scheduler**](https://github.com/facebook/react)\r\nCopyright \u0026copy; Facebook, Inc. and its affiliates.\r\nLicense: [MIT](https://github.com/facebook/react/blob/master/LICENSE)\r\n\r\n[**node-uuid**](https://github.com/kelektiv/node-uuid)\r\nCopyright \u0026copy; 2010-2016 Robert Kieffer and other contributors\r\nLicense: [MIT](https://github.com/kelektiv/node-uuid/blob/master/LICENSE.md)\r\n\r\nTo regenerate the dependencies use by this package, run the following command:\r\n\r\n```sh\r\nnpx license-checker --production --json | jq 'map_values({ licenses, publisher, repository }) | del(.[][] | nulls)'\r\n```\r\n\r\n### Contributing\r\n\r\nPlease see [CONTRIBUTING](./CONTRIBUTING.md) for more information.\r\n\r\n### Credits\r\n\r\nFirst-party code subject to copyrights held by Optimizely, Inc. and its contributors and licensed to you under the terms of the Apache 2.0 license.\r\n\r\n### Other Optimizely SDKs\r\n\r\n- Agent - https://github.com/optimizely/agent\r\n\r\n- Android - https://github.com/optimizely/android-sdk\r\n\r\n- C# - https://github.com/optimizely/csharp-sdk\r\n\r\n- Flutter - https://github.com/optimizely/optimizely-flutter-sdk\r\n\r\n- Go - https://github.com/optimizely/go-sdk\r\n\r\n- Java - https://github.com/optimizely/java-sdk\r\n\r\n- JavaScript - https://github.com/optimizely/javascript-sdk\r\n\r\n- PHP - https://github.com/optimizely/php-sdk\r\n\r\n- Python - https://github.com/optimizely/python-sdk\r\n\r\n- Ruby - https://github.com/optimizely/ruby-sdk\r\n\r\n- Swift - https://github.com/optimizely/swift-sdk\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foptimizely%2Freact-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foptimizely%2Freact-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foptimizely%2Freact-sdk/lists"}