Security News
PyPI Introduces Digital Attestations to Strengthen Python Package Security
PyPI now supports digital attestations, enhancing security and trust by allowing package maintainers to verify the authenticity of Python packages.
@splitsoftware/splitio-redux
Advanced tools
A library to easily use Split JS SDK with Redux and React Redux
A library to easily use Splitio JS SDK with Redux and React Redux. It provides helper functions over Splitio JS SDK, so that you don't need to directly access the SDK factory and client.
INTERNAL COMMENT: several library features were adapted from the Webconsole project.
The /examples
folder includes two working apps with Redux and React-Redux:
$ npm install
$ npm run build
$ cd examples/react-redux-spa
/examples/react-redux-spa$ yarn install
/examples/react-redux-spa$ yarn start
...
$ cd examples/react-redux-ssr
/examples/react-redux-ssr$ npm install
/examples/react-redux-ssr$ npm run dev
As a PoC and for testing purposes, the library was integrated to the Admin and Login apps of the Webconsole
project, and partially integrated to the Main app.
Follow the steps below to run it:
$ npm run build
$ npm link
...
/webconsole$ git fetch
/webconsole$ git checkout sdk_redux_library_migration
/webconsole$ npm link react-sdk-library
/webconsole$ npm start
/webconsole$ npm test
$ npm install redux redux-thunk react-redux @splitsoftware/splitio-redux
$ yarn add redux redux-thunk react-redux @splitsoftware/splitio-redux
Note: react-redux
is only necessary for some features of the library. Check them in section Usage with React Redux.
To use the library, we need to pass the splitReducer
to the store and the Thunk
middleware to handle async actions.
A first action must be dispatched to initialize the Splitio SDK, invoking the initSplitSdk
action creator.
Below is a simple example for creating a redux store:
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import thunk from 'redux-thunk'
import { initSplitSdk, reducer as splitReducer } from '@splitsoftware/splitio-redux'
// Instantiate the store
const storeInstance = createStore(
combineReducers({
splitio: splitReducer
/* You'll have your app reducers here too. */
}),
// The library uses async actions that require Thunk middleware
composeEnhancers(applyMiddleware(thunk))
);
// Split config, with the same format than the one provided to Split factory.
const splitBrowserConfig = {
core: {
authorizationKey: 'YOUR_BROWSER_API_KEY',
key: 'user_key'
}
};
// Dispatch action to initilize Splitio SDK
storeInstance.dispatch(initSplitSdk(splitBrowserConfig));
Note: initSplitSdk
is an async action creator that initialize the SDK. For scenarios where more than one store is created, such as server rendering, invoke initSplitSdk
once and dispatch its result on each new store:
Example:
const splitServerConfig = {
core: {
authorizationKey: 'YOUR_SDK_API_KEY'
}
};
const asyncAction = initSplitSdk(splitServerConfig);
const app = express();
app.get('*', (req, res) => {
// A new store is created per request
const store = createStore(reducers, initialState, applyMiddleware(thunk));
store.dispatch(asyncAction);
...
}
The Split reducer updates a piece of state with the following shape:
{
// 'splitio' is the key where the Split reducer is mounted
'splitio': {
// The following properties indicates the current status of the SDK
'isReady': true; // boolean indicating if the SDK has triggered an SDK_READY event
'isTimedout': false; // boolean indicating if the SDK has triggered an SDK_TIMEDOUT event
'lastUpdate': 12312312312; // timestamp of the last SDK event (SDK_READY, SDK_TIMEDOUT or SDK_UPDATED)
/* The 'treatments' property contains the evaluations of Splits.
* Each evaluation is associated with an Split name and a key (e.g., user id or organization name).
* Thus the property has 3 levels: split name, split key, and finally the treatment that was evaluated for that split and key.
*/
'treatments': { // First level: list of evaluated splits
'split_name_1': { // Second level: list of evaluated keys for the container split
'user_key': { // Third level: evaluated treatment, formed by a 'treatment' value and a config that might be null
'treatment': 'on',
'config': '{ ... }'
},
'org_key': {
'treatment': 'on',
'config': '{ ... }'
}
},
'split_name_2': {
'user_key': {
'treatment': 'treatment_A',
'config': null
}
}
}
}
}
INTERNAL COMMENTS:
treatments
property without the second level.treatments
property could be structured with the levels split key -> split name -> treatment
instead of split name -> split key -> treatment
.treatments
property, in order to reduce redundancy (different keys for the same split could evaluate to the same treatment).[TODO: DOCUMENT ACTION CREATORS FOR SERVER-SIDE]
initSplitSdk
This action creator initializes the Splitio SDK. It accepts a configuration param and returns a Thunk (async) action.
function initSplitSdk: (params: {
config: IBrowserSettings;
onReady?: () => any;
onTimedout?: () => any;
onUpdate?: () => any;
}) => ThunkAction
config
: setting object used to initialize the Split factory.
onReady
, onTimedout
and onUpdate
are optional callback functions that will be invoked on SDK_READY, SDK_READY_TIMEDOUT and SDK_UPDATE events respectively.
getTreatments
This action creator performs a treatment evaluation, i.e., it invokes the actual client.getTreatment*
methods. It accepts a param with the different objects required for an evaluation, and returns either a plain action (FSA) with the result of the evaluation, or an async action if the SDK is not ready yet.
function getTreatments: (params: {
key?: SplitKey;
splitNames: string[] | string;
attributes?: Attributes;
evalOnUpdate?: boolean;
}) => ThunkAction | FluxStandardAction
key
: optional split key. If not provided, it defaults to the key defined in the SDK setting, i.e., the config object passed to initSplitSdk
.
splitNames
: split name or array of split names to evaluate.
attributes
: optional map of attributes passed to the actual client.getTreatment*
methods.
evalOnUpdate
: indicates to re-evaluate the splits if the SDK is updated. For example, a true
value might be the desired behaviour for permission toggles or operation toggles, such as a kill switch, that you want to inmediately reflect in your app. A false
value might be useful for experiment or release toggles, where you want to keep the treatment unchanged during the sesion of the user. The param is true
by default.
[TODO: DOCUMENT TRACK FOR SERVER-SIDE]
track
This function track events, i.e., it invokes the actual client.track*
methods. It accepts a param with the different objects required for an event tracking, and returns a boolean value indicating whether or not the SDK was able to successfully queue the event to be sent back to Split servers.
function track: (params: {
key?: SplitKey;
trafficType?: string;
eventType: string;
value?: number;
properties?: Properties;
}) => boolean
key
: optional split key. If not provided, it defaults to the key defined in the SDK config object.
trafficType
: the traffic type of the key in the track call. If not provided, it defaults to the traffic type defined in the SDK config object. If not provided either in the SDK setting, the function logs an error message and returns false.
eventType
, value
and properties
follow the same rules then the client.track*
method params.
getSplitNames
Returns the names of Splits registered with the SDK. The array might be empty if the SDK was not initialized (by dispatching a "initSplitSdk" action) or if it's not ready yet.
function getSplitNames(): string[]
selectTreatmentValue
and selectTreatmentWithConfig
These functions extract a treatment evaluation from the Split state. The first one returns the treatment string value, and the second one a treatment object containing its value and configuration. See Get Treatments with Configurations for details.
function selectTreatmentValue(splitState: ISplitState, splitName: string, key?: SplitKey, defaultValue?: string): string
function selectTreatmentWithConfig(splitState: ISplitState, splitName: string, key?: SplitKey, defaultValue?: TreatmentWithConfig): TreatmentWithConfig
splitState
: Split piece of state from the store.
splitName
: split name.
key
: optional split key. If not provided, it returns the first evaluation done for splitName
.
defaultValue
: the value to return if the treatment is not found in the store (the getTreatment
evaluation was not performed for the given split and key). It defaults to 'control'
for the first selector, and { treatment: 'control', config: null}
for the second.
INTERNAL COMMENTS:
actionToggler
function in Webconsole could be also included as helper function.The library provides some functions to connect your React components to Split pieces of state and functionality.
These functions use the connect() method, thus you need to include react-redux
in the project.
mapTreatmentToProps
function mapTreatmentToProps(splitName: string, key?: SplitKey, getSplitState?: IGetSplitState): (state: any) => { feature: string }
This function returns a mapStateToProps
function to be used with connect
. As a result, a string property named feature
will be merged as prop for the connected component. Its value will be the treatment value evaluated for the given splitName
and key
.
getSplitState
is a optional function that takes the entire Redux state and returns the state slice which corresponds to where the Split reducer was mounted. This functionality is rarely needed, and defaults to assuming that the reducer is mounted under the splitio
key.
Example:
import { mapTreatmentToProps } from '@splitsoftware/splitio-redux';
export default connect(mapTreatmentToProps('split_name'))(component);
mapIsFeatureOnToProps
function mapIsFeatureOnToProps(splitName: string, key?: SplitKey, getSplitState?: IGetSplitState): (state: any) => { isFeatureOn: string }
This function also returns a mapStateToProps
function to be used with connect
. As a result, a boolean property named isFeatureOn
will be merged as prop for the connected component. Its value will be true
if the treatment for the given splitName
and key
evaluated to 'on'
, or false
otherwise.
getSplitState
is a optional function that takes the entire Redux state and returns the state slice which corresponds to where the Split reducer was mounted. This functionality is rarely needed, and defaults to assuming that the reducer is mounted under the splitio
key.
Example:
import { mapIsFeatureOnToProps } from '@splitsoftware/splitio-redux';
export default connect(mapIsFeatureOnToProps('split_name'))(component);
connectToggler
function connectToggler(splitName: string, key?: SplitKey, getSplitState?: IGetSplitState):
(ComponentOn: React.ComponentType, ComponentOff: React.ComponentType ) => React.ComponentType
The connectToggler
connector returns a HOC function given a splitName
, and an optional key
and getSplitState
function.
The returned HOC accepts two components as input and returns a wrapper component that will render ComponentOn
component if the treatment for the given split name and key is 'on'
, or ComponentOff
component otherwise.
If key
is not provided, the treatment value of the first evaluation of splitName
split is considered.
getSplitState
is a function that takes the entire Redux state and returns the state slice which corresponds to where the Split reducer was mounted. This param defaults to assuming that the reducer is mounted under the splitio
key.
Example:
import { connectToggler } from '@splitsoftware/splitio-redux';
const ConnectedFeatureTogler = connectToggler(SPLIT_NAME)(FeatureComponent, LegacyComponent);
connectSplit
function connectSplit(getSplitState?: IGetSplitState):
(component: React.ComponentType) => React.ComponentType
This decorator connects your components with:
splitio
. See Split state for details.getTreatments
, binded to the dispatch
of your store. See getTreatments for details.Example:
import { connectSplit, selectTreatmentValue } from '@splitsoftware/splitio-redux';
class MyComponent extends React.Component {
componentDidMount() {
this.props.getTreatments({ splitNames: 'my_split' });
};
renderOn() { ... }
renderOtherwise() { ... }
render() {
selectTreatmentValue(this.props.splitio, 'my_split') === 'on' ?
renderOn() : renderOtherwise();
}
};
export default connectSplit()(myComponent);
actionToggler
Licensed under the Apache License, Version 2.0. See: Apache License.
Split is the leading Feature Delivery Platform for engineering teams that want to confidently deploy features as fast as they can develop them. Split’s fine-grained management, real-time monitoring, and data-driven experimentation ensure that new features will improve the customer experience without breaking or degrading performance. Companies like Twilio, Salesforce, GoDaddy and WePay trust Split to power their feature delivery.
To learn more about Split, contact hello@split.io, or get started with feature flags for free at https://www.split.io/signup.
Split has built and maintains SDKs for:
For a comprehensive list of open source projects visit our Github page.
Learn more about Split:
Visit split.io/product for an overview of Split, or visit our documentation at help.split.io for more detailed information.
FAQs
A library to easily use Split JS SDK with Redux and React Redux
The npm package @splitsoftware/splitio-redux receives a total of 4,155 weekly downloads. As such, @splitsoftware/splitio-redux popularity was classified as popular.
We found that @splitsoftware/splitio-redux demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 6 open source maintainers collaborating on the project.
Did you know?
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.
Security News
PyPI now supports digital attestations, enhancing security and trust by allowing package maintainers to verify the authenticity of Python packages.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.