• This repository has been archived on 30/Mar/2023
  • Stars
    star
    116
  • Rank 303,894 (Top 6 %)
  • Language
    JavaScript
  • License
    Other
  • Created almost 7 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A React component library for easy product analytics instrumentation (deprecated)

react-amplitude

Travis npm

A React component library for easy product analytics instrumentation.

Project Status

react-amplitude is not an officially supported Amplitude SDK or library, and deprecated now.

Please use our offical Typescript SDK to track with React!

The problems with traditional, imperative event-based logging

  • Contextual event information (i.e. "event properties") often require lots of plumbing to the code path where the events are logged, requiring more code and breaking encapsulation.
  • Similarly, it can be difficult to provide contextual information to events fired in low-level, reusable components (e.g. Buttons, Dropdowns, Links, etc.).
  • Traditional event-based analytics logging often use imperative APIs, which can sometimes require more code and be more painful when writing declarative React components.

The problems with "autotrack" solutions

  • Autotrack solutions can be unreliable, as they may depend on attributes that engineers may unintentionally change (like CSS selectors).
  • Autotrack solutions may unintentionally track sensitive user data.
  • Autotrack can't capture all kinds of events, so you may end up requiring to implement manual event logging.

The solution

react-amplitude has a modern, declarative API to make it easy to instrument new events and properties with Amplitude. It takes advantage of core React features to propagate contextual information down through the component hierarchy. This makes it far less painful to add new event properties to existing events.

Unlike "autotrack" solutions, react-amplitude does require some code changes in order to start sending data to Amplitude. However, it aims to minimize the amount of code required to start collecting data and make instrumentation seem less like a chore.

If you use common reusable components in your React application like Buttons, Dropdowns, Links, etc., you should be able to achieve "autotrack"-like instrumentation with just a few lines of code. And from there, it can be really simple to instrument new properties and context throughout your application, giving you the same flexibility as manual event logging.

Example: Instrumenting Tic-Tac-Toe (From Facebook's Intro to React Tutorial)

Events logged:

  • start game
  • game won
  • click square
  • jump to move
  • go to game start

Event properties:

  • scope (array; "square", "history", "game")
  • moves made (number)
  • winner ("X" or "O")
  • current player ("X" or "O")
import React from "react";
import { render } from "react-dom";
import amplitude from "amplitude-js";
import {
  AmplitudeProvider,
  Amplitude,
  LogOnMount
} from "@amplitude/react-amplitude";

const AMPLITUDE_KEY = "";

function Square(props) {
  return (
    <Amplitude
      eventProperties={inheritedProps => ({
        ...inheritedProps,
        scope: [...inheritedProps.scope, "square"]
      })}
    >
      {({ instrument }) => (
        <button
          className="square"
          onClick={instrument("click square", props.onClick)}
        >
          {props.value}
        </button>
      )}
    </Amplitude>
  );
}

class Board extends React.Component {
  renderSquare(i) {
    return (
      <Square
        value={this.props.squares[i]}
        onClick={() => this.props.onClick(i)}
      />
    );
  }

  render() {
    return (
      <div>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
        </div>
        <div className="board-row">
          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}
        </div>
        <div className="board-row">
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
        </div>
      </div>
    );
  }
}

class Game extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      history: [
        {
          squares: Array(9).fill(null)
        }
      ],
      stepNumber: 0,
      xIsNext: true
    };
  }

  handleClick(i) {
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    const current = history[history.length - 1];
    const squares = current.squares.slice();
    if (calculateWinner(squares) || squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext ? "X" : "O";
    this.setState({
      history: history.concat([
        {
          squares: squares
        }
      ]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext
    });
  }

  jumpTo(step) {
    this.setState({
      stepNumber: step,
      xIsNext: step % 2 === 0
    });
  }

  render() {
    const history = this.state.history;
    const current = history[this.state.stepNumber];
    const winner = calculateWinner(current.squares);

    const moves = history.map((step, move) => {
      const desc = move ? "Go to move #" + move : "Go to game start";
      return (
        <li key={move}>
          <Amplitude
            eventProperties={inheritedProps => ({
              ...inheritedProps,
              scope: [...inheritedProps.scope, "move button"]
            })}
          >
            {({ logEvent }) => (
              <button
                onClick={() => {
                  logEvent(move ? "jump to move" : "go to game start");
                  this.jumpTo(move);
                }}
              >
                {desc}
              </button>
            )}
          </Amplitude>
        </li>
      );
    });

    let status;
    if (winner) {
      status = "Winner: " + winner;
    } else {
      status = "Current player: " + (this.state.xIsNext ? "X" : "O");
    }

    return (
      <AmplitudeProvider
        amplitudeInstance={amplitude.getInstance()}
        apiKey={AMPLITUDE_KEY}
      >
        <Amplitude
          eventProperties={{
            scope: ["game"],
            "moves made": this.state.step,
            "current player": this.state.xIsNext ? "X" : "O",
            winner
          }}
        >
          <LogOnMount eventType="start game" />
          {!!winner && <LogOnMount eventType="game won" />}
          <div className="game">
            <div className="game-board">
              <Board
                squares={current.squares}
                onClick={i => this.handleClick(i)}
              />
            </div>
            <Amplitude
              eventProperties={inheritedProps => ({
                ...inheritedProps,
                scope: [...inheritedProps.scope, "history"]
              })}
            >
              <div className="game-info">
                <div>{status}</div>
                <ol>{moves}</ol>
              </div>
            </Amplitude>
          </div>
        </Amplitude>
      </AmplitudeProvider>
    );
  }
}

// ========================================

render(<Game />, document.getElementById("root"));

function calculateWinner(squares) {
  const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6]
  ];
  for (let i = 0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
      return squares[a];
    }
  }
  return null;
}

Edit nnowj5nonj

Installation

With npm:

npm install --save @amplitude/react-amplitude

With yarn:

yarn add @amplitude/react-amplitude

react-amplitude does not come with its own copy of the Amplitude JavaScript SDK. You can either install the Amplitude SDK via npm or with a JavaScript snippet.

API

AmplitudeProvider props

amplitudeInstance

A required prop. You should be providing an Amplitude instance returned from the Amplitude JS SDK's getInstance method.

apiKey

An optional prop that can be used to initialize the Amplitude instance with the provided key.

userId

An optional prop that can be used to attribute all events to a specific user.

Amplitude props

children

If can pass a function as the children prop, it will be called with a single object parameter, and the return value of that function will be used for rendering the actual React subtree.

The single object parameter has two useful fields: logEvent and instrument.

logEvent is a function that can be used to imperatively log events. All event properties from this component's eventProperties prop and any inherited properties will be included in these events.

Example:

function Button(props) {
  return (
    <Amplitude>
      {({ logEvent }) =>
        <button
          onClick={() => {
            logEvent('button click');
            props.onClick();
          }}
        >
          {props.children}
        </button>
      }
    </Amplitude>
  )
}

instrument is a function that can be used to declaratively log events. If you have pre-existing event handlers, just wrap the functions with an instrument, and events will fire every time your normal event handlers are executed. instrument takes two parameters, the event type and the function to proxy.

instrument is also useful if you would like to prevent re-rendering via shouldComponentUpdate optimizations like PureComponent. It memoizes its arguments and returns the same function instance across re-renders. For this reason, it's not recommended to use instrument for functions that change on every render (i.e. inlined or "arrow" functions in render).

Example:

function Button(props) {
  return (
    <Amplitude>
      {({ instrument }) =>
        <button
          onClick={instrument('button click', props.onClick)}
        >
          {props.children}
        </button>
      }
    </Amplitude>
  )
}

eventProperties

If an object is provided, the object will be merged with event properties higher-up in the component hierarchy and included in all events logged in this component or any components in its subtree.

If a function is provided, it will be called with a single parameter, inheritedProperties, that contains all of the event properties from components higher in the React component hierarchy. The return value from this function will be used for all logged events in this component or other components in its subtree.

debounceInterval

If provided, events logged by the component will be debounced by this amount, in milliseconds.

userProperties

An optional object that if provided, will trigger updates to the current user's "user properties."

LogOnMount props

eventType

When this component mounts, it will log an event with this value as the event type.

eventProperties

These properties will be applied to the event when the component mounts.

instanceName

THe Amplitude instance to log events to.

LogOnChange props

value

Required prop, that when changes (diffing is done with shallow equality comparison), logs an event.

eventType

When the value prop changes, it will log an event with this value as the event type.

eventProperties

These properties will be applied to the event when the component mounts.

instanceName

The Amplitude instance to log events to.

License

MIT

Friends & Related Projects

  • analytics-react: Write analytics code once with Segment and collect customer data from any source and send it to over 250+ destinations.

More Repositories

1

redux-query

A library for managing network state in Redux
JavaScript
1,103
star
2

Amplitude-JavaScript

JavaScript SDK for Amplitude
JavaScript
305
star
3

Amplitude-iOS

Native iOS/tvOS/macOS SDK
Objective-C
303
star
4

Amplitude-Android

Native Android SDK for Amplitude
Java
160
star
5

Amplitude-TypeScript

TypeScript Amplitude Analytics SDK
TypeScript
132
star
6

Amplitude-Flutter

Official Amplitude Flutter SDK
Dart
89
star
7

Amplitude-ReactNative

Official Amplitude React Native SDK
TypeScript
81
star
8

Amplitude-Node

Server-side Node.js SDK for Amplitude
TypeScript
68
star
9

unity-plugin

Official Amplitude Unity Plugin
C++
42
star
10

Amplitude-Swift

Native iOS/tvOS/macOS/watchOS SDK
Swift
32
star
11

Amplitude-Kotlin

Amplitude Kotlin SDK
Kotlin
28
star
12

Amplitude-Flutter-Deprecated

Amplitude's Flutter SDK
Dart
27
star
13

Amplitude-Python

Python Amplitude Analytics SDK
Python
22
star
14

GTM-Web-Demo

Web demo app for Google Tag Manager + Amplitude integration
HTML
19
star
15

amplitude-dev-center

Amplitude's Developer Center docs.
HTML
18
star
16

itly-sdk

Iteratively Analytics SDK for browsers and Node — JavaScript & TypeScript
TypeScript
18
star
17

analytics-go

Go Amplitude Analytics SDK
Go
11
star
18

ampli-examples

Example apps using the Ampli SDK
Java
9
star
19

Amplitude-Unreal

Unreal Engine SDK/Plugin for Amplitude
Objective-C
8
star
20

storybook-addon-amplitude

JavaScript
8
star
21

GTM-Android-Demo

Android demo app for Google Tag Manager + Amplitude integration
Java
8
star
22

experiment-js-client

Amplitude Experiment client-side SDK for JavaScript
TypeScript
7
star
23

amplitude-gtm-template

Smarty
6
star
24

itly-sdk-ios

Iteratively Analytics SDK for iOS — Swift & Objective-C
Swift
6
star
25

Amplitude-Java

Official Amplitude Java SDK
Java
6
star
26

experiment-react-native-client

React Native Client SDK for Amplitude Experiment
TypeScript
6
star
27

amplitude-js-gtm

Amplitude JS wrapper for GTM custom template
JavaScript
5
star
28

experiment-android-client

Kotlin
4
star
29

itly-sdk-jvm

Iteratively Analytics SDK for JVM — Android, Kotlin & Java
Kotlin
4
star
30

amplitude-figma

Personal workspace for amplitude figma
TypeScript
4
star
31

experiment-go-server

Amplitude Experiment Server-side SDK for Go
Go
4
star
32

GTM-iOS-Demo

iOS demo app for Google Tag Manager + Amplitude integration
Objective-C
4
star
33

experiment-implementation-examples

A repository of examples implementations of Amplitude Experiment
TypeScript
3
star
34

experiment-python-server

Amplitude Experiment Python Server SDK
Python
3
star
35

amplitude-server-gtm-template

Amplitude Server Side GTM Template
Smarty
3
star
36

experiment-ios-client

Swift
3
star
37

itly-sdk-ruby

Iteratively SDK for Ruby
Ruby
2
star
38

experiment-node-server

TypeScript
2
star
39

GTM-cross-domain-script

HTML
2
star
40

ai-product-hackathon

Documentation and starter code for the 2023 AI x Product Hackathon
Python
2
star
41

homebrew-ampli

Homebrew Formulae for Ampli CLI
Ruby
2
star
42

experiment-evaluation

Kotlin multiplatform experiment evaluation library
Kotlin
2
star
43

itly-sdk-python

Iteratively Analytics SDK for Python
Python
2
star
44

experiment-jvm-server

Amplitude Experiment Server-side SDK for the Java and Kotlin
Kotlin
2
star
45

experiment-ruby-server

Amplitude Experiment Ruby Server SDK
Ruby
2
star
46

experiment-php-server

Amplitude Experiment PHP Server SDK
PHP
2
star
47

amplitude-browser-sdk-gtm-template

The amplitude GTM template with @amplitude/analytics-browser internal
Smarty
2
star
48

amplitude-ios-core

Swift
1
star
49

iOS-Demo-Carthage

iOS demo app testing Carthage support for Amplitude-iOS SDK
Objective-C
1
star
50

Android-Demo

Simple tilt maze game with Amplitude integration
Java
1
star
51

corona-plugin

Amplitude plugin for Corona
Lua
1
star
52

chrome-extension-demo

JavaScript
1
star
53

skylab-reactnative-client

Java
1
star
54

Segment-Android-Demo

Java
1
star
55

skylab-button-demo

Demo for moving a button
JavaScript
1
star
56

evaluation-proxy-helm

A Helm chart for deploying the Amplitude Experiment Evaluation Proxy on Kubernetes.
Smarty
1
star
57

amplitude-win

Amplitude SDK for Windows Apps
C#
1
star