react-abkit
v1.0.5
Published
Modern A/B testing library with variant assignment and real-time config updates
Downloads
109
Maintainers
Readme
react-abkit
Modern A/B testing library with variant assignment and real-time config updates for React applications.
🚀 Features
- ✅ TypeScript Support - Full type safety with TypeScript
- ✅ React Hooks - Easy integration with React components
- ✅ Deterministic Assignment - Consistent user experience across sessions
- ✅ Local Storage - Persistent variant assignments
- ✅ Lightweight - Minimal bundle size
- ✅ Framework Agnostic Core - Use with any JavaScript framework
- ✅ Custom Storage Adapters - Extend with your own storage solution
📦 Installation
npm install react-abkit🔧 Quick Start
1. Basic Usage with React Hooks
Wrap app with provider
import React from "react";
import { ABTestProvider, useExperiment } from "react-abkit";
function App() {
const abTest = new ABTest({
logger: LokiLogger,
flagAdapter: configCatAdapter,
});
return (
<ABTestProvider abTest={abTest}>
<MyMainComponent />
</ABTestProvider>
);
}
export const ABBoxColorCurrentUser: React.FC<Props> = ({ experimentKey }) => {
const { variant } = useExperiment(experimentKey);
if (variant === "blue") {
return <ABBoxBlue />;
}
if (variant === "pink") {
return <ABBoxPink />;
}
if (variant === "orange") {
return <ABBoxOrange />;
}
};
asdf2. Direct Usage
import { ABTest, UserManager, LocalStorageAdapter } from "react-abkit";
// Initialize AB testing
const storage = new LocalStorageAdapter();
const userManager = new UserManager(storage);
// Initialize user
userManager.initializeUser(
"user123",
{
email: "[email protected]",
plan: "premium",
},
experimentConfigs
);
// Get variant for experiment
const variant = userManager.getVariant("pricing-test");
console.log(`User is in variant: ${variant}`);📚 API Reference
Types
import type {
UserData,
ExperimentConfig,
VariantType,
ABTestConfig,
Logger,
} from "react-abkit";Core Classes
ABTest
Main class for A/B testing functionality.
UserManager
Manages user state and variant assignments.
// Initialize user
const user = userManager.initializeUser("user123", {
email: "[email protected]",
country: "US",
});
// Get assigned variant
const variant = userManager.getVariant("experiment-key");
// Update user attributes
// note: second option reassign variant for current user
userManager.updateUser(newUserData, true);LocalStorageAdapter
Default storage adapter using browser's localStorage.
React Hooks
useExperiment(experimentKey: string)
Get variant assignment for an experiment.
const { variant, isVariant, isControl, isExperiment } =
useExperiment("my-test");useExperimentWithManager(userManager: UserManager, experimentKey: string)
Use experiment with a specific UserManager instance.
🏗️ Advanced Usage
Custom Storage Adapter
import { StorageAdapter } from "react-abkit";
class CustomStorageAdapter implements StorageAdapter {
load(key: string): string | null {
// Your custom load logic
return customStorage.get(key);
}
save(key: string, value: string): void {
// Your custom save logic
customStorage.set(key, value);
}
remove(key: string): void {
// Your custom remove logic
customStorage.delete(key);
}
}With Logging
import { type Logger } from "react-abkit";
export const LokiLogger: Logger = {
info: (msg, ctx) => sendToLoki({ level: "info", message: msg, ctx }),
warn: (msg, ctx) => sendToLoki({ level: "warn", message: msg, ctx }),
error: (msg, err, ctx) =>
sendToLoki({
level: "error",
message: msg,
error: err,
ctx,
}),
debug: (msg, ctx) => sendToLoki({ level: "debug", message: msg, ctx }),
};
class ConfigCatAdapter implements FeatureFlagAdapter {
private client: configcat.IConfigCatClient;
constructor(sdkKey: string) {
this.client = configcat.getClient(sdkKey);
}
async getFlag(key: string): Promise<boolean> {
try {
return await this.client.getValueAsync(key, false);
} catch (error) {
console.error("[ConfigCatAdapter] Failed to fetch flag:", key, error);
return false;
}
}
onFlagChange(key: string, callback: (value: boolean) => void): void {
this.client.on("configChanged", async () => {
const value = await this.getFlag(key);
callback(value);
});
}
}
const abTest = new ABTest({
logger: LokiLogger,
flagAdapter: configCatAdapter,
});With FeatureFlag
import { type FeatureFlagAdapter } from "react-abkit";
class ConfigCatAdapter implements FeatureFlagAdapter {
private client: configcat.IConfigCatClient;
constructor(sdkKey: string) {
this.client = configcat.getClient(sdkKey);
}
async getFlag(key: string): Promise<boolean> {
try {
return await this.client.getValueAsync(key, false);
} catch (error) {
console.error("[ConfigCatAdapter] Failed to fetch flag:", key, error);
return false;
}
}
onFlagChange(key: string, callback: (value: boolean) => void): void {
this.client.on("configChanged", async () => {
const value = await this.getFlag(key);
callback(value);
});
}
}
const abTest = new ABTest({
flagAdapter: configCatAdapter,
});🧪 Testing
The library includes comprehensive test coverage. Run tests with:
npm test📄 License
MIT
🤝 Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📞 Support
- Create an issue for bug reports
- Check discussions for questions
Made with ❤️ by Dinmukhammed
