Skip to content

Instantly share code, notes, and snippets.

@akdetrick
Last active August 30, 2018 20:12
Show Gist options
  • Save akdetrick/4c6d4373ea2633664b7d6e64b54e68c5 to your computer and use it in GitHub Desktop.
Save akdetrick/4c6d4373ea2633664b7d6e64b54e68c5 to your computer and use it in GitHub Desktop.
React component for A/B testing
/**
* This is some feature component in which we're running
* two experiments, `radExperiment` and `coolExperiment`.
*
* Each experiment can either be `true` (variant), or
* `false` (control). The service probably runs more than
* one control, but the front end need only know if
* it's getting "variant" or not.
*/
const FeatureComponent = (props) => {
const {
experiments,
} = this.props;
return (
<dl>
<dt>Is this user in coolExperiment variant?</dt>
{experiments.coolExperiment
? <dd>Cool Variant!</dd>
: <dd>Cool Control.</dd>
}
<dt>Is this user in radExperiment variant?</dt>
{experiments.radExperiment
? <dd>Rad Variant!</dd>
: <dd>Rad Control.</dd>
}
</dl>
);
}
// the `withExperiments` HOC adds the `experiments` prop to the wrapped component
export.default FeatureComponentWithExperiment = withExperiments(
FeatureComponent,
['coolExperiment', 'radExperiment']
);
/* this should live in `src/client/modules/common/decorators/withExperiment` */
/**
* @param {ReactElement} WrappedComponent component that will be provided `experiments` prop
* @param {Array} experimentNames experiment name strings
*/
const withExperiments = (WrappedComponent, experimentNames) => {
// define the prop as an object with the shape;
// {
// experimentName1: Boolean(user in variant?),
// experimentName2: Boolean(user in variant?),
// }
//
const experimentsProp = experimentNames
.reduce((obj, name) => {
// getExperimentState could be checking app state,
// dispatching an action, selector, or something else that
// provides information about the state of the experiment
// for the current user
obj[name] = getExperimentState(name);
// The experiment service should always return "control" for errors
// or undefined experiments. The front end _should not_ define a
// default value here; the service should be the point of truth.
}, {});
const ComponentWithExperiment = (props) => (
<WrappedComponent
experiments={experimentsProp}
{...props}
/>
);
ComponentWithExperiment.propTypes = {
experiments: PropTypes.object
};
return ComponentWithExperiment;
};
export default withExperiment;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment