UNPKG

redux-ab-test

Version:

A/B testing React components with Redux and debug tools. Isomorphic with a simple, universal interface. Well documented and lightweight. Tested in popular browsers and Node.js. Includes helpers for React, Redux, and Segment.io

86 lines (74 loc) 3.27 kB
import React from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { play, activate, deactivate, } from '../../module'; import { logger } from './logger'; import { groupChildrenByName, requireChildrenAreVariations, } from './selectors'; class LoadedComponent extends React.Component { static propTypes = { // Name of the experiment experimentName: React.PropTypes.string.isRequired, variationName: React.PropTypes.string.isRequired, // Experiment and Variation objects passed to the play / activate / deactivate action-creators: experiment: ImmutablePropTypes.map, variation: ImmutablePropTypes.map, // React element to render: children: requireChildrenAreVariations, // Bound Action Creators play: React.PropTypes.func.isRequired, activate: React.PropTypes.func.isRequired, deactivate: React.PropTypes.func.isRequired, }; render() { const { experimentName, variationName, children } = this.props; logger(`${__filename}: Rendering Experiment experimentName='${experimentName}', variationName='${variationName}'`); // Group the children by name const childrenByName = groupChildrenByName(children); logger(`${__filename}: Experiment experimentName='${experimentName}', variationName='${variationName}' has children with names='${Object.keys(childrenByName)}'`); // Find the Variation with the matching name const child = childrenByName[variationName] || null; if (!child) { throw new Error(`variationName=${variationName} not found`); } // Return the Variation logger(`${__filename}: Rendered Experiment experimentName='${experimentName}', variationName='${variationName}'`); return child; } // // Component Lifecycle // // Record the experiment will be mounted componentWillMount() { const { experimentName, variationName, experiment, variation, play } = this.props; logger(`${__filename}: componentWillMount: Experiment experimentName='${experimentName}', variationName='${variationName}'`); if (play && experiment && variation) { play({ experiment, variation }); } } // Record we mounted the experiment componentDidMount() { const { experimentName, variationName, experiment, activate } = this.props; logger(`${__filename}: componentDidMount: Experiment experimentName='${experimentName}', variationName='${variationName}'`); if (activate && experiment) { activate({ experiment }); } } // Record we un-mounted the experiment componentWillUnmount() { const { experimentName, variationName, experiment, deactivate } = this.props; logger(`${__filename}: componentWillUnmount: Experiment experimentName='${experimentName}', variationName='${variationName}'`); if (deactivate && experiment) { deactivate({ experiment }); } } } const mapDispatchToProps = dispatch => bindActionCreators({ play, activate, deactivate }, dispatch); export default connect(null, mapDispatchToProps)(LoadedComponent);