Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@wework/we-experiment-react

Package Overview
Dependencies
Maintainers
26
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@wework/we-experiment-react

React helpers for we-experiment-js.

  • 1.4.2
  • unpublished
  • latest
  • npm
  • Socket score

Version published
Weekly downloads
0
Maintainers
26
Weekly downloads
 
Created
Source

WeExperiment React

React helpers for we-experiment-js.

Installation

Install using NPM:

npm install --save @wework/we-experiment-react

Usage

The main use-case for this library is using a Redux store.

Redux Setup

This library requires that an experiments reducer be mounted at the top-level of your store, under the key experiments.

A helper is provided for creating a reducer for the experiments, which is setup like so:

import { combineReducers, createStore } from 'redux';
import { combineExperiments } from 'we-experiment-react';
import reducers from 'reducers';

/*
  Assuming reducers is an object in the form of:
  {
    foo: reducer1,
    bar: reducer2,
    ...
  }
 */

const withExperimentsReducer = combineExperiments(reducers);

/*
  Resulting withExperimentsReducer is now:
  {
    foo: reducer1,
    bar: reducer2,
    ...
    experiments: experimentsReducer,
  }
 */

const rootReducer = combineReducers(withExperimentsReducer);

const store = createStore(rootReducer);

Alternatively, you can import the reducer directly and use it as you would normally:

import { combineReducers, createStore } from 'redux';
import { reducer as experimentsReducer } from 'we-experiment-react';

const rootReducer = {
  experiments: experimentsReducer,
  // your other reducers here
}

const store = createStore(rootReducer)

Fetch experiments

Experiments may be hydrated manually or fetched using a helper function which in turn uses we-experiment-js.

import { initExperiments, fetchExperiments } from 'we-experiment-react';

// Manual hydration:
const experiments = {
  foo: 'control',
  bar: 'variant_1',
};

store.dispatch(initExperiments(experiments));

// Fetch experiments:
const experimentNames = ['EXPERIMENT_1', 'EXPERIMENT_2'];

store.dispatch(fetchExperiments('USER_ID', 'SPLIT_API_KEY', experimentNames /*, options */));

Note that in order to use fetchExperiments, support for Promises is required for the Redux setup, for example, using redux-thunk.
Alternatively, it may be run like so:

fetchExperiments('USER_ID', 'SPLIT_API_KEY', experimentNames /*, options */)(store.dispatch);

See we-experiment-js's documentation for details on the available options.

Update experiments

It's possible to update the experiments fetched using fetchExperiments, using refreshExperiments. The refreshExperiments function should be called only after calling fetchExperiments. This function allows you to fetch new experiments or update existing ones, passing attributes that will be added to or override the ones passed on the call to fetchExperiments.

If any existing experiment names are passed, their value will be reset until the actual results are fetched.

import { fetchExperiments, refreshExperiments } from 'we-experiment-react';

// Fetch experiments:
const experimentNames = ['EXPERIMENT_1', 'EXPERIMENT_2'];

store.dispatch(fetchExperiments('USER_ID', 'SPLIT_API_KEY', experimentNames /*, options */));

// At this point, we have the results for EXPERIMENT_1, EXPERIMENT_2

// Update / fetch experiments:
const experimentsToUpdate = ['EXPERIMENT_2', 'EXPERIMENT_3'];
// Attributes will be added to or override the attributes passed to the initial `fetchExperiments`
// call, for this call only
const attributes = {};
store.dispatch(refreshExperiments(experimentsToUpdate, attributes));

// At this point, we have the results for EXPERIMENT_1, EXPERIMENT_2, EXPERIMENT_3.
// EXPERIMENT_2 has updated results, using the new attributes that were passed

Experiment Component

An Experiment component is provided for use-cases where a simple component replacement is required:

import { Experiment, Control, Variant } from 'we-experiment-react';

const experiment = (
  <Experiment name="EXPERIMENT_1">
    <Control>
      <Foo />
    </Control>
    <Variant name="variant_1">
      <Bar />
    </Variant>
  </Experiment>
);

ReactDOM.render(experiment, document.getElementById('container'));

Alternatively, Experiment may receive a render prop as its child:

<Experiment name="EXPERIMENT_1">
  {
    (variant) => variant === 'on' ? <Foo /> : <Bar />
  }
</Experiment>

Experiment Higher-Order Component

We provide 2 HOC's to retrieve experiments from store connectExperiment and connectExperiments

connectExperiment
import React from 'react';
import { connectExperiment } from 'we-experiment-react';

class Foo extends React.Component {
  render() {
    const variant = this.props.exp;

    if (!variant) {
      // Experiment is off.
      return null;
    }

    switch (variant) {
      case 'control':
        return <Bar />;
      case 'variant_1':
        return <Baz />;
    }
  }
}
Foo.propTypes = {
  exp: PropTypes.string,
};

export default connectExperiment('exp')(Foo);

By default, the variant will be passed as a prop with the same name as the experiment.

It is also possible to pass a propName option to change the prop's name:

export default connectExperiment('exp', { propName: 'woot' })(Foo);
connectExperiments
import React from 'react';
import { connectExperiments } from 'we-experiment-react';

class Foo extends React.Component {
  render() {
    const {
      exp1,
      exp2,
    } = this.props;
    
    if (exp1 === 'on' && exp2 === 'on') {
      return <div>Experiments are 'on'</div>;
    }
    
    return <div>Experiments are 'off'</div>;
  }
}

export default connectExperiments({
  exp1: true,
  exp2: true,
})(Foo);

By default, the variant will be passed as a prop with the same name as the experiment.

It is also possible to pass a prop name as value or propName option in object to change the prop's name:


export default connectExperiments({
  exp1:  'expX',
  exp2: {
    propName: 'expZ',
  },
})(Foo);

FeatureFlag Component

A FeatureFlag component is provided for simpler use-cases where only an on/off experiment exists.

This component will display its children only if the provided experiment's group equals to the activeValue prop's value (default: "on").

<FeatureFlag name="FEATURE_2">
  <Foo />
</FeatureFlag>

Feature HOC

In addition to the above component, a matching feature HOC is provided to allow same behavior at the component level.

export default feature('exp')(Foo);

This HOC also accepts an object as its optional second argument, with an activeValue key (default: "on") which behaves the same as the above component's prop of the same name.

FAQs

Package last updated on 16 Jun 2020

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc