@datanova/react
Version:
React SDK for event tracking and A/B testing with Datanova
451 lines (439 loc) • 13.5 kB
TypeScript
import { Datanova, EventsService, ExperimentsService, Variant } from '@datanova/browser';
export { ConsoleEventsService, DatanovaEventsService, DatanovaExperimentsService, Event, EventType, EventsService, ExperimentsService, NoopEventsService, RandomExperimentsService, SDKConfig, Variant, generateAnonymousId } from '@datanova/browser';
import * as react_jsx_runtime from 'react/jsx-runtime';
import * as react from 'react';
import { ReactNode, ReactElement, MouseEvent, FormEvent } from 'react';
declare function createDatanova(apiKey: string): Datanova;
declare function createDatanova(config: {
eventsService?: EventsService;
experimentsService?: ExperimentsService;
}): Datanova;
/**
* Hook to access Datanova analytics tracking methods.
* Must be used within a DatanovaProvider component.
*
* @returns Object containing track, trackClick, trackPageView, trackImpression, trackSubmit, trackChange, identify, and reset methods
*
* @example
* ```jsx
* import { useDatanova } from '@datanova/react';
*
* function MyComponent() {
* const { trackClick, identify, reset } = useDatanova();
*
* const handleClick = () => {
* trackClick('Button Clicked', { buttonId: 'submit' });
* };
*
* const handleLogin = (userId, plan) => {
* // Simple identify with just userId
* identify(userId);
*
* // Or with user properties (v1.7.0+)
* identify(userId, { plan });
* };
*
* const handleLogout = () => {
* reset();
* };
*
* return <button onClick={handleClick}>Track Event</button>;
* }
* ```
*
* @throws {Error} If used outside of a DatanovaProvider
*/
declare function useDatanova(): {
trackClick: (eventName: string, properties?: Record<string, unknown>) => void;
trackPageView: (eventName: string, properties?: Record<string, unknown>) => void;
trackImpression: (eventName: string, properties?: Record<string, unknown>) => void;
trackSubmit: (eventName: string, properties?: Record<string, unknown>) => void;
trackChange: (eventName: string, properties?: Record<string, unknown>) => void;
identify: (userId: string, properties?: Record<string, unknown>) => void;
reset: () => void;
};
type ExperimentState = {
isLoading: true;
data: undefined;
error: null;
} | {
isLoading: false;
data: Variant;
error: null;
} | {
isLoading: false;
data: 'control';
error: Error;
};
/**
* Hook to get and track A/B test experiment variants.
* Automatically tracks experiment exposure and manages loading/error states.
*
* SSR-safe: During server-side rendering, this hook returns null
* to avoid hydration mismatches. The actual variant is fetched client-side.
*
* @param experimentId - The numeric ID of the experiment
* @returns Object containing variant, loading state, and error
*
* @example
* ```jsx
* import { useVariant } from '@datanova/react';
*
* function MyComponent() {
* const { loading, data, error } = useVariant({ experimentId: 20 });
*
* if (loading) return <div>Loading...</div>;
* if (error) return <div>Error: {error.message}</div>;
*
* return (
* <div>
* {data === 'variant' ? (
* <NewFeature />
* ) : (
* <OldFeature />
* )}
* </div>
* );
* }
* ```
*/
declare function useVariant({ experimentId }: {
experimentId: number;
}): ExperimentState;
/**
* Props for the DatanovaProvider component
*/
interface DatanovaProviderProps {
value: Datanova;
children: ReactNode;
}
/**
* Provider component that provides Datanova tracking methods to child components.
* Must be placed at the root of your component tree.
*
* @remarks
* The DatanovaProvider uses React Context to make the Datanova instance available
* throughout your application. Initialize the Datanova instance outside of your
* component tree to prevent re-initialization on re-renders.
*
* @example
* Basic usage with SDK key:
* ```jsx
* import { createReactDatanova, DatanovaProvider } from '@datanova/react';
*
* // Simple initialization with SDK key
* const datanova = createReactDatanova("your-sdk-key");
*
* function App() {
* return (
* <DatanovaProvider value={datanova}>
* <YourApp />
* </DatanovaProvider>
* );
* }
* ```
*
* @example
* Advanced usage with custom services:
* ```jsx
* import { createReactDatanova, DatanovaProvider } from '@datanova/react';
* import { DatanovaEventsService, DatanovaExperimentsService } from '@datanova/browser';
*
* // Custom configuration with specific services
* const datanova = createReactDatanova({
* eventsService: new YourEventsService(),
* experimentsService: new YourExperimentsService()
* });
*
* function App() {
* return (
* <DatanovaProvider value={datanova}>
* <YourApp />
* </DatanovaProvider>
* );
* }
* ```
*
* @example
* Development usage with ConsoleEventsService:
* ```jsx
* import { createReactDatanova, DatanovaProvider } from '@datanova/react';
* import { ConsoleEventsService } from '@datanova/browser';
*
* // Use ConsoleEventsService for development/debugging
* const datanova = createReactDatanova({
* eventsService: new ConsoleEventsService()
* });
*
* function App() {
* return (
* <DatanovaProvider value={datanova}>
* <YourApp />
* </DatanovaProvider>
* );
* }
* ```
*
* @param props - The provider props
* @param props.value - The Datanova instance to provide to child components
* @param props.children - The child components that will have access to the Datanova instance
*/
declare function DatanovaProvider({ value, children }: DatanovaProviderProps): react_jsx_runtime.JSX.Element;
/**
* Props for the TrackPageView component
*/
interface TrackPageViewProps {
/** Event name to track when the component mounts */
eventName: string;
/** Optional properties to include with the event */
properties?: Record<string, unknown>;
}
/**
* Component that tracks a page view event when it mounts.
* The browser SDK automatically captures page metadata like URL, title, and referrer.
*
* @example
* ```jsx
* import { TrackPageView } from '@datanova/react';
*
* function HomePage() {
* return (
* <>
* <TrackPageView eventName="Home Page Viewed" />
* <h1>Welcome to our site</h1>
* </>
* );
* }
* ```
*
* @example
* ```jsx
* // With additional properties
* function ProductPage({ productId }) {
* return (
* <>
* <TrackPageView
* eventName="Product Page Viewed"
* properties={{ productId, category: 'electronics' }}
* />
* <ProductDetails />
* </>
* );
* }
* ```
*/
declare function TrackPageView({ eventName, properties }: TrackPageViewProps): null;
/**
* Props for the TrackClick component
*/
interface TrackClickProps {
children: ReactElement<{
onClick?: (event: MouseEvent) => void;
}>;
/** Event name to track when the element is clicked */
eventName: string;
/** Optional properties to include with the event */
properties?: Record<string, unknown>;
}
/**
* Component that tracks click events on its child element.
* Wraps a single React element and tracks when it's clicked, preserving any existing onClick handler.
*
* @example
* ```jsx
* import { TrackClick } from '@datanova/react';
*
* function CTAButton() {
* return (
* <TrackClick eventName="CTA Clicked" properties={{ location: 'header' }}>
* <button onClick={() => console.log('Original handler')}>
* Get Started
* </button>
* </TrackClick>
* );
* }
* ```
*
* @throws {Error} If children is not a valid React element
*/
declare function TrackClick({ children, eventName, properties }: TrackClickProps): ReactElement<{
onClick?: (event: MouseEvent) => void;
}, string | react.JSXElementConstructor<any>>;
/**
* Props for the TrackImpression component
*/
interface TrackImpressionProps {
children: ReactNode;
/** Event name to track when the element comes into view */
eventName: string;
/** Optional properties to include with the event */
properties?: Record<string, unknown>;
/** Percentage of element that must be visible to trigger (0-1). Default: 0.5 (50%) */
threshold?: number;
/** Whether to track only the first impression. Default: true */
triggerOnce?: boolean;
}
/**
* Component that tracks when its children come into the viewport using Intersection Observer.
* Useful for tracking impressions of content blocks, images, or any visual elements.
*
* @example
* ```jsx
* import { TrackImpression } from '@datanova/react';
*
* function HeroSection() {
* return (
* <TrackImpression eventName="Hero Section Viewed">
* <section className="hero">
* <h1>Welcome to Our Product</h1>
* <p>Start your journey today</p>
* </section>
* </TrackImpression>
* );
* }
* ```
*
* @example
* ```jsx
* // Track when 80% of element is visible, multiple times
* <TrackImpression
* eventName="Product Card Viewed"
* properties={{ productId: '123' }}
* threshold={0.8}
* triggerOnce={false}
* >
* <ProductCard />
* </TrackImpression>
* ```
*
* @example
* ```jsx
* // Track lazy-loaded content
* <TrackImpression
* eventName="Comments Section Viewed"
* threshold={0.1} // Track when just 10% is visible
* >
* <LazyComments />
* </TrackImpression>
* ```
*/
declare function TrackImpression({ children, eventName, properties, threshold, triggerOnce, }: TrackImpressionProps): react_jsx_runtime.JSX.Element;
/**
* Props for the TrackSubmit component
*/
interface TrackSubmitProps {
children: ReactElement<{
onSubmit?: (event: FormEvent) => void;
}>;
/** Event name to track when the form is submitted */
eventName: string;
/** Optional properties to include with the event */
properties?: Record<string, unknown>;
}
/**
* Component that tracks submit events on form elements.
* Wraps a form element and tracks when it's submitted, preserving any existing onSubmit handler.
*
* @example
* ```jsx
* import { TrackSubmit } from '@datanova/react';
*
* function ContactForm() {
* return (
* <TrackSubmit eventName="Contact Form Submitted" properties={{ type: 'inquiry' }}>
* <form onSubmit={(e) => { e.preventDefault(); console.log('Form submitted'); }}>
* <input type="email" name="email" required />
* <button type="submit">Submit</button>
* </form>
* </TrackSubmit>
* );
* }
* ```
*
* @throws {Error} If children is not a valid React element
*/
declare function TrackSubmit({ children, eventName, properties }: TrackSubmitProps): ReactElement<{
onSubmit?: (event: FormEvent) => void;
}, string | react.JSXElementConstructor<any>>;
/**
* Props for the TrackChange component
*/
interface TrackChangeProps {
children: ReactElement<{
onChange?: (value: unknown) => void;
}>;
/** Event name to track when the element value changes */
eventName: string;
/** Optional properties to include with the event */
properties?: Record<string, unknown>;
}
/**
* Component that tracks change events on form elements.
* Wraps a form element (select, input, etc.) and tracks when its value changes,
* preserving any existing onChange handler.
*
* @example
* ```jsx
* import { TrackChange } from '@datanova/react';
*
* function FilterForm() {
* return (
* <TrackChange eventName="Date Filter Changed" properties={{ filter: 'date' }}>
* <select onChange={(e) => console.log('Selected:', e.target.value)}>
* <option value="7d">Last 7 days</option>
* <option value="30d">Last 30 days</option>
* </select>
* </TrackChange>
* );
* }
* ```
*
* @throws {Error} If children is not a valid React element
*/
declare function TrackChange({ children, eventName, properties }: TrackChangeProps): ReactElement<{
onChange?: (value: unknown) => void;
}, string | react.JSXElementConstructor<any>>;
interface ExperimentProps {
/** The numeric ID of the experiment */
experimentId: number;
/** Content to show for the control variant */
control: ReactNode;
/** Content to show for the variant */
variant: ReactNode;
/** Optional content to show while loading */
loading?: ReactNode;
/** Optional content to show on error */
error?: ReactNode;
}
/**
* Component for declarative A/B testing.
* Automatically handles experiment assignment and tracks exposure.
*
* @example
* ```jsx
* import { Experiment } from '@datanova/react';
*
* function HomePage() {
* return (
* <Experiment
* experimentId={20}
* control={<OldHero />}
* variant={<NewHero />}
* />
* );
* }
* ```
*
* @example With loading and error states
* ```jsx
* <Experiment
* experimentId={20}
* control={<OldCheckout />}
* variant={<NewCheckout />}
* loading={<CheckoutSkeleton />}
* error={<OldCheckout />} // Fallback to control on error
* />
* ```
*/
declare function Experiment({ experimentId, control, variant: variantContent, loading: loadingContent, error: errorContent, }: ExperimentProps): react_jsx_runtime.JSX.Element;
export { DatanovaProvider, Experiment, TrackChange, type TrackChangeProps, TrackClick, type TrackClickProps, TrackImpression, type TrackImpressionProps, TrackPageView, type TrackPageViewProps, TrackSubmit, type TrackSubmitProps, createDatanova, useDatanova, useVariant };