react-alpha-beta
Version:
Simple declarative A/B testing component for React.
143 lines (110 loc) • 4.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _Cohort = require('./Cohort');
var _constants = require('./constants');
var _Experiment = require('./Experiment');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @fileOverview Given two variants of React Component (or Element), it displays
* the appropriate one depending on the experiment context.
*/
var ABComponent = function (_React$Component) {
(0, _inherits3.default)(ABComponent, _React$Component);
// cohortStore: React.PropTypes.object,
function ABComponent(props) {
(0, _classCallCheck3.default)(this, ABComponent);
var _this = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(ABComponent).call(this, props));
_this.successAction = function () {
// TODO: Move this up to be a method
var variant = _this.state.isInCohort ? 'b' : 'a';
var experimentId = _this.props.experimentParams.id;
(0, _Experiment.postExperimentData)(experimentId, variant, true);
if (_this.props.successAction) {
var _this$props;
(_this$props = _this.props).successAction.apply(_this$props, arguments);
}
};
_this.onStorageEvent = function (event) {
if (event.key === _constants.localStorageKey) {
_this.setState({
isInCohort: (0, _Cohort.isInCohort)(_this.props.experimentParams)
});
}
};
_this.state = {
isInCohort: false
};
return _this;
}
(0, _createClass3.default)(ABComponent, [{
key: 'componentWillMount',
value: function componentWillMount() {
this.setState({
isInCohort: (0, _Cohort.isInCohort)(this.props.experimentParams)
});
global.addEventListener('storage', this.onStorageEvent);
}
}, {
key: 'componentDidMount',
value: function componentDidMount() {
// Determine an exposable label for the fields shown
// TODO: Make this a bit more user facing
var variant = this.state.isInCohort ? 'b' : 'a';
// Record that the AlphaBeta component was loaded
var experimentId = this.props.experimentParams.id;
(0, _Experiment.postExperimentData)(experimentId, variant, false);
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
global.removeEventListener('storage', this.onStorageEvent);
}
}, {
key: 'renderElementOrComponent',
/**
* Whether it is passed React element or React component, it renders accordingly.
* It also injects `successAction` into the props.
* @param {React.Component|React.element} elemOrComp
* @return {React.element}
*/
value: function renderElementOrComponent(elemOrComp) {
var props = {
successAction: this.successAction
};
return _react2.default.isValidElement(elemOrComp) ? _react2.default.cloneElement(elemOrComp, props) : _react2.default.createElement(elemOrComp, props);
}
}, {
key: 'render',
value: function render() {
var _props = this.props;
var ComponentA = _props.ComponentA;
var ComponentB = _props.ComponentB;
return this.state.isInCohort ? this.renderElementOrComponent(ComponentB) : this.renderElementOrComponent(ComponentA);
}
}]);
return ABComponent;
}(_react2.default.Component);
ABComponent.displayName = 'ABComponent';
ABComponent.propTypes = {
experimentParams: _react2.default.PropTypes.object,
// ComponentA/B can be either React element or React component.
ComponentA: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.element,
// https://github.com/facebook/react/issues/5143#issuecomment-147473269
_react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.func])]),
ComponentB: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.element, _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.func])]),
successAction: _react2.default.PropTypes.func };
exports.default = ABComponent;