@udacity/ureact-experiments v0.0.1
ureact-experiments
React components to help run A/B tests and feature flags.
Currently built based on Optimizely.
Usage
<OptimizelyProvider>
The OptimizelyProvider component is a wrapper that will instantiate everything you need to run A/B tests or feature flags with Optimizely.
Paramter | Type | Description |
---|---|---|
user | object: { id: string; attributes?: { key: string: any } } | (Required) User ID and attributes to be passed to Optimizely for bucketing, etc. |
projectId | string | (Optional) The Optimizely Project ID to use for any nested experiments and feature flags. Will default to the default "Udacity" project in Optimizely if not provided. |
import React from 'react';
import {
OptimizelyProvider,
} from '@udacity/ureact-experiments'
class AppWrapper extends React.Component {
render() {
return (
<OptimizelyProvider
user={{
id: 'user123',
attributes: {
'device': 'iPhone',
'is_logged_in': true
}
}}
projectId='project-123'
>
<App />
</OptimizelyProvider>
)
}
}
<Experiment>
The Experiment component will determine what variant of the given experiment the current user should see.
Paramter | Type | Description |
---|---|---|
experimentKey | string | (Required) The experiment key. |
attributes | object | (Optional) Attributes for the user. Will override attributes supplied to the OptimizelyProvider . |
defaultComponent | ReactNode | (Optional) A component to show if the variation is undefined (still loading) or null (user was not bucketed in experiment). |
If your experiment logic and components are simple, you can use the child render function provided:
import React from 'react';
import { Experiment } from '@udacity/ureact-experiments'
class MyComponent extends React.Component {
render() {
return (
<Experiment key='experiment_key'>
{(variation) => (
variation === 'purple_button'
? <PurpleButton />
: <BoringWhiteButton />
)}
</Experiment>
)
}
}
However, if your logic or component code is more complex, you may want to use the Variation
component along with it:
import React from 'react';
import { Experiment } from '@udacity/ureact-experiments'
class MyComponent extends React.Component {
render() {
return (
<Experiment key='experiment_key'>
<Variation key='control'>
<BoringWhiteButton />
</Variation>
<Variation key='blue_button'>
<BlueButton />
</Variation>
<Variation key='purple_button'>
<PurpleButton />
</Variation>
</Experiment>
)
}
}
<FeatureFlag>
The FeatureFlag component will determine whether or not the given feature flag is enabled for the current user.
Paramter | Type | Description |
---|---|---|
key | string | (Required) The key of the feature flag. |
attributes | object | (Optional) Attributes for the user. Will override attributes supplied to the OptimizelyProvider . |
Children of the <FeatureFlag>
will only be shown if the feature is enabled:
import React from 'react';
import { FeatureFlag } from '@udacity/ureact-experiments'
class MyComponent extends React.Component {
render() {
return (
<FeatureFlag key='feature_name'>
<p>My feature is enabled!</p>
</FeatureFlag>
)
}
}
Alternatively, if you want to be able to show a component when the feature is not enabled, you can use the child render function:
import React from 'react';
import { FeatureFlag } from '@udacity/ureact-experiments'
class MyComponent extends React.Component {
render() {
return (
<FeatureFlag key='feature_name'>
{(enabled) => (
enabled
? <p>My feature is enabled!</p>
: <p>Feature is not enabled.</p>
)}
</FeatureFlag>
)
}
}
Debugging
Why is my experiment variation always "null"?
If you are always getting a variation of null
, you may want to check the following:
- Make sure you are passing in the correct
projectId
to theOptimizelyProvider
. If you are not using the default "Udacity" project in Optimizely, you must pass in the project ID. - Make sure your experiment is on for the environment you are using
- Make sure your traffic allocation is not set to 0% for your experiment
Contributing
Development
# Compile the package
npm run build
# Preview a demo of the components
npm start
# Run tests
npm test
# Lint the code
npm run lint
Watching Changes
To continually see your updates on the demo site, you will need to run two commands at once.
This is because we need to compile the code under /demo (to get the components and render a real app) in addition to compiling the actual package (under /src).
# Run the build and watch files for changes
npm run build
# In another terminal, run the dev server
npm start
Releasing
If you are testing a new feature, you should only release a prerelease
version.
Once a prerelease has been tested, you can release a real version from the master
branch.
Run the release command and follow the prompts. This will update the version, tag it, and publish to NPM for you.
npm run release
Notes
You may be aware that there is in fact a React SDK built by Optimizely, which is very similar to this one. Here are some reasons we decided to go ahead and create our own version of it.
- Experiments-API benefits: This library interacts directly with Udacity's experiments-api. It is deployed to a CloudFlare worker which makes it very performant, but it also does quite a few things for us that we didn't want to have to re-implement in every web app:
- Initializes Optimizely with a datafile, and keeps that datafile up-to-date via webhooks
- Allows for multiple project IDs to be used (not possible with the Optimizely react-sdk).
- Fires Segment events for you (upon Experiment/Feature activation, etc)
- Consistency: Any Udacity services that need to fetch experiment data will (or should) use the
experiments-api
. It is nice to have the front end applications use the same API for the sake of consistency and developer understanding. - Future considerations: Other than the
<OptimizelyProvider>
component, we have tried to keep the rest of the components provider-agnostic. If we ever choose to move off of Optimizely, it shouldn't be hard to add a new provider component and continue using this library.
4 years ago