diff --git a/README.md b/README.md index 1ca0a90..114ed32 100644 --- a/README.md +++ b/README.md @@ -78,10 +78,27 @@ Split allows you to [implement a custom impression listener](https://help.split. ## Usage -Now assuming you have a split named: `feature1` you can do something like: +Now assuming you have a split named `feature1` you can do something like: -```jsx - +### Hook + +```tsx +const [feature1, config] = useSplit('feature1'); +if (feature1 === 'on') { + return ; +} +``` + +Optional [attributes](https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#attribute-syntax) +can also be passed in: +```tsx +const [feature1, config] = useSplit('feature1', { paying_customer: true }); +``` + +### Component + +```tsx + {(value: TreatmentWithConfig) => value.treatment === 'on' ? this.renderComponent() : null } @@ -90,7 +107,7 @@ Now assuming you have a split named: `feature1` you can do something like: You can optionally pass a list of splits: -```jsx +```tsx {(values: TreatmentsWithConfig) => { console.log(values); @@ -103,6 +120,17 @@ You can optionally pass a list of splits: ``` +### Tracking + +We have a `useTrack` hook which returns the a function with the same signature as +[`client.track`](https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#track). +```tsx +const track = useTrack(); +function handleClick() { + const queued = track('user', 'click', 'the_button', { foo: 'bar' }); +} +``` + ## Contributing ### Fork and Clone the Project diff --git a/src/Split.tsx b/src/Split.tsx index 00f1764..4167efc 100644 --- a/src/Split.tsx +++ b/src/Split.tsx @@ -1,6 +1,6 @@ -import React from 'react'; +import { useContext } from 'react'; import { SplitContext } from './SplitProvider'; -import { ISplitContextValues, ISplitProps } from './types'; +import { ISplitProps } from './types'; /** * Component that will receive a split prop, connect on SplitContext and return treatment when SDK is ready. @@ -12,20 +12,17 @@ import { ISplitContextValues, ISplitProps } from './types'; * {(value: TreatmentWithConfig) => value.treatment === 'on' ? this.renderComponent() : null} * */ -const Split: React.SFC = ({ name, children }) => ( - - {({ client, isReady, lastUpdate }: ISplitContextValues) => - children( - client && isReady - ? name instanceof Array - ? client.getTreatmentsWithConfig(name as string[]) - : client.getTreatmentWithConfig(name as string) - : null, - client, - lastUpdate, - ) - } - -); +const Split = ({ name, children }: ISplitProps) => { + const { client, isReady, lastUpdate } = useContext(SplitContext); + return children( + client && isReady + ? name instanceof Array + ? client.getTreatmentsWithConfig(name as string[]) + : client.getTreatmentWithConfig(name as string) + : null, + client, + lastUpdate, + ); +}; export default Split; diff --git a/src/index.ts b/src/index.ts index af6711e..91a3b48 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,4 @@ export { default as Split } from './Split'; export { default as SplitProvider, SplitContext } from './SplitProvider'; +export * from './useSplit'; +export * from './useTrack'; diff --git a/src/useSplit.ts b/src/useSplit.ts new file mode 100644 index 0000000..6aff259 --- /dev/null +++ b/src/useSplit.ts @@ -0,0 +1,33 @@ +import { + Attributes, + TreatmentWithConfig, +} from '@splitsoftware/splitio/types/splitio'; +import { useContext, useEffect, useState } from 'react'; +import { SplitContext } from './SplitProvider'; + +/** + * Returns a treatment and it's config. + * @param {string} splitName - The string that represents the split we want to get the treatment. + * @param {Attributes=} attributes - An object of type Attributes defining the attributes for the given key. + * @returns {[string, string | null]} Tuple with treatment first and config second. + */ +export const useSplit = ( + splitName: string, + attributes?: Attributes, +): [string, string | null] => { + const { client, isReady, lastUpdate } = useContext(SplitContext); + const [{ treatment, config }, setTreatment] = useState(defaultTreatment); + useEffect(() => { + const next = + client && isReady + ? client.getTreatmentWithConfig(splitName, attributes) + : defaultTreatment; + setTreatment(next); + }, [client, isReady, lastUpdate]); + return [treatment, config]; +}; + +const defaultTreatment: TreatmentWithConfig = { + config: null, + treatment: 'control', // SplitIO's default value +}; diff --git a/src/useTrack.ts b/src/useTrack.ts new file mode 100644 index 0000000..9a353a5 --- /dev/null +++ b/src/useTrack.ts @@ -0,0 +1,10 @@ +import { IClient } from '@splitsoftware/splitio/types/splitio'; +import { useContext } from 'react'; +import { SplitContext } from './SplitProvider'; + +export const useTrack: () => IClient['track'] = () => { + const { client, isReady } = useContext(SplitContext); + return client && isReady ? client.track : defaultTrack; +}; + +const defaultTrack = () => false;