Skip to content

Instantly share code, notes, and snippets.

@ahallora
Last active March 27, 2024 08:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ahallora/cc449765fda3d75792627802ca785534 to your computer and use it in GitHub Desktop.
Save ahallora/cc449765fda3d75792627802ca785534 to your computer and use it in GitHub Desktop.
Basic React ABTesting Component - POC
import React, { ReactNode, useState } from "react";
type Experiment = {
exposure: number;
render: ({ success }: { success: any }) => any;
name?: string;
};
enum TestEvent {
"VIEW" = "View",
"SUCCESS" = "Success",
}
type Props = {
name: string;
experiments: Experiment[];
};
const ABTest = ({ name, experiments }: Props) => {
const [renderedExperiment, setRenderedExperiment] = useState<
JSX.Element | ReactNode | Element | undefined
>(undefined);
const triggerEvent = (
event: TestEvent,
experimentNumber: number,
experimentName?: string
) => () => {
console.log("🧪 ABTest", { name, event, experimentNumber, experimentName });
};
const pickExperiment = () => {
const rand = Math.random();
let totalExposure = 0;
const selectedExperiment = experiments.find(experiment => {
totalExposure += experiment.exposure;
return rand <= totalExposure;
});
return selectedExperiment || null;
};
const renderExperiment = () => {
const experiment = pickExperiment();
if (!experiment) {
console.error("Error: No experiment was picked.");
return null;
}
const { render, name: experimentName } = experiment;
const experimentNumber = experiments.indexOf(experiment) + 1;
triggerEvent(TestEvent.VIEW, experimentNumber, experimentName)();
return render({
success: triggerEvent(
TestEvent.SUCCESS,
experimentNumber,
experimentName
),
});
};
if (renderedExperiment === undefined) {
setRenderedExperiment(renderExperiment());
}
return <>{renderedExperiment}</>;
};
export default ABTest;
import ABTest from './ABTest';
const App = () => (
<ABTest
name="favfood"
experiments={[
{
exposure: 0.5,
name: 'pizza',
render: ({ success }) => (
<div>
<button onClick={success}>🍕</button>
<button>🍿</button>
</div>
),
},
{
exposure: 0.5,
name: 'popcorn',
render: ({ success }) => (
<div>
<button onClick={success}>🍿</button>
<button>🍕</button>
</div>
),
},
]}
/>
);
export default App;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment