Skip to content

Commit

Permalink
Move to use context API (#259)
Browse files Browse the repository at this point in the history
* Move to use context API
  • Loading branch information
roderickhsiao authored Apr 26, 2021
1 parent 45a45cd commit 01106be
Show file tree
Hide file tree
Showing 52 changed files with 10,727 additions and 1,887 deletions.
7 changes: 5 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
"plugins": [
"dynamic-import-node",
"syntax-dynamic-import",
"@babel/plugin-transform-spread",
"@babel/plugin-proposal-class-properties"
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-transform-spread"
],
"env": {
"dist": {
Expand Down
8 changes: 5 additions & 3 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ module.exports = {
'no-use-before-define': 0,
'import/no-named-as-default': 0,
'import/no-named-as-default-member': 0,
'react/no-find-dom-node': 0
'react/no-find-dom-node': 0,
'react/prop-types': 0
},
env: {
browser: true,
node: true,
es6: true,
jasmine: true,
es6: true
jest: true,
node: true
},
plugins: ['import', 'react', 'react-hooks'],
parser: 'babel-eslint'
Expand Down
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ node_js:
after_success:
# - "npm run func"
- "cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js"
install:
- yarn
32 changes: 17 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

Typically, you have to manually add instrumentation code throughout your application, e.g., hooking up `onClick` handlers to the links you want to track. `react-i13n` provides a simplified approach by letting you define the data model you want to track and handling the beaconing for you.

`react-i13n` does this by building an [instrumentation tree](#i13n-tree) that mirrors your applications React component hierarchy. All you have to do is leverage our [React component or mixin](./docs/guides/integrateWithComponents.md) to denote which components should fire the tracking events.
`react-i13n` does this by building an [instrumentation tree](#i13n-tree) that mirrors your applications React component hierarchy. All you have to do is leverage our [React component](./docs/guides/integrateWithComponents.md) to denote which components should fire the tracking events.

## Features

Expand Down Expand Up @@ -46,7 +46,7 @@ in order to support all browsers and older versions of Node.js. We recommend usi
* (Optionally) follow the [event system](./docs/guides/eventSystem.md) if you want to fire events manually.

```js
import React from 'react';
import React, { Component } from 'react';
import {
ReactI13n,
createI13nNode,
Expand All @@ -55,34 +55,38 @@ import {
import somePlugin from 'some-i13n-plugin'; // a plugin for a certain instrumentation mechanism

// create a i13n anchor for link tracking
// or you can use the mixin to track an existing component
const I13nAnchor = createI13nNode('a', {
isLeafNode: true,
bindClickEvent: true,
follow: true
isLeafNode: true,
bindClickEvent: true,
follow: true
});

class DemoApp extends React.Component {
componentWillMount () {
this.props.i13n.executeEvent('pageview', {}); // fire a custom event
class DemoApp extends Component {
componentDidMount () {
// fire a custom event
this.props.i13n.executeEvent('pageview', {});
}

render() {
...
<span>
<I13nAnchor
href="http://foo.bar"
i13nModel={{action: 'click', label: 'foo'}}
i13nModel={{
action: 'click',
label: 'foo'
}}
>
...
</I13nAnchor>
// this link will be tracked, and the click event handlers provided by the plugin will get the model data as
// {site: 'foo', action: 'click', label: 'foo'}
</span>
}
};


const I13nDempApp = setupI13n(DemoApp, {
rootModelData: {site: 'foo'},
rootModelData: { site: 'foo' },
isViewportEnabled: true
}, [somePlugin]);

Expand All @@ -99,7 +103,7 @@ Or follow our guide and [create your own](./docs/guides/createPlugins.md).
## I13n Tree
![I13n Tree](https://cloud.githubusercontent.com/assets/3829183/7980892/0b38eb70-0a60-11e5-8cc2-712ec42089fc.png)

`react-i13n` builds the instrumentation tree by leveraging the undocumented React `context` feature and the `componentWillMount` life cycle event. Each component can define a `i13nModel` prop that defines the data it needs to track. This approach is more performant, as it means you do not need additional DOM manipulation when you want to collect the tracking data values for sending out beacons.
`react-i13n` builds the instrumentation tree by leveraging the React `context` feature. Each component can define a `i13nModel` prop that defines the data it needs to track. This approach is more performant, as it means you do not need additional DOM manipulation when you want to collect the tracking data values for sending out beacons.

Since the i13n data is defined at each level. Whenever you want to get the `i13nModel` for a certain node, `react-i13n` will traverse back up the tree to merge all the `i13nModel` information in the hierarchy. Since the tree is already built, you do not need extra DOM access, which is cheap and efficient.

Expand All @@ -113,8 +117,6 @@ link-wrapped-with-react-component x 111,056 ops/sec ±1.55% (88 runs sampled)
link-wrapped-with-react-component-with-i13n-high-order-component x 64,422 ops/sec ±1.95% (84 runs sampled)
```

We recommend to use [createI13nNode](./docs/api/createI13nNode.md#createi13nnodecomponent-options) instead of I13nMixin as it performs better. As the benchmark result, on server side, rendering `64` react components with i13n functionalities takes `1 ms`. Let's say it takes `3 ms` overhead if you have `200` links on the page. That's a trade off if you want to organize i13n implementation better with react-i13n. We are working on performance improvement, if you have any insight or performance benchmark, please let us know!

## Presentation
Take a look at [Rafael Martins' slides](http://www.slideshare.net/RafaelMartins21/instrumentation-talk-39547608) from a recent React meetup to understand more.

Expand Down
6 changes: 3 additions & 3 deletions docs/api/setupI13n.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ We provide `setupI13n` as a convenient [higher order function](https://medium.co
* `plugins` - plugins array that you defined according to the definition below.

```js
import React from 'react';
import React, { Component } from 'react';
import { setupI13n } from 'react-i13n';
import someReactI13nPlugin from 'some-react-i13n-plugin';

class DemoApp extends React.Component({
class DemoApp extends Component({
...
});

Expand All @@ -40,4 +40,4 @@ If you have multiple React trees in one page, we will create multiple i13n trees

### Util Functions

You will get i13n util functions automatically via `this.props.i13n` by using `setupI13n`, more detail please refer to [util functions](../guides/utilFunctions.md).
`options.skipUtilFunctionsByProps` - true to prevent i13n util function to be passed via `props.i13n`
14 changes: 6 additions & 8 deletions docs/guides/utilFunctions.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
## Util Functions

We provides util functions for you to easily access the resource provided by `react-i13n`, you have two options to get the util functions,

- `props` - When you are using [setupI13n](../api/setupI13n.md) or [createI13nNode](../api/createI13nNode.md), we will pass util functions via `this.props.i13n`. Please note that starts from `2.3.0`, you can pass `skipUtilFunctionsByProps=true` to prevent `props.i13n` being passed to fix the unknown props warning from `[email protected]`.
- `context` - You can always define `contextTypes` and access util functions via `context`, i.e., `this.context.i13n`.
We provides util functions for you to easily access the resource provided by `react-i13n`, you can get util function via
// @TODO, update use react context
`props` - When you are using [setupI13n](../api/setupI13n.md) or [createI13nNode](../api/createI13nNode.md), we will pass util functions via `this.props.i13n`. Please note that starts from `2.3.0`, you can pass `skipUtilFunctionsByProps=true` to prevent `props.i13n` being passed to fix the unknown props warning from `[email protected]`.

```js
// with setupI13n or createI13nNode, you will automatically get this.props.i13n for i13n util functions
Expand All @@ -13,19 +12,18 @@ class DemoComponent extends React.Component {
// this.props.i13n.getI13nNode() to access the i13nNode created by createI13nNode
// this.props.i13n.executeEvent() to execute i13n event
}
};
}

const I13nDemoComponent = createI13nNode(DemoComponent);
```

```js

// For components without `setupI13n` and `createI13nNode`, you can still get i13n functions via context
import { I13nContext } from 'react-i13n';
class DemoComponent extends React.Component {
displayName = 'DemoComponent',;
contextTypes = {
i13n: React.PropTypes.object
};
static contextType = I13nContext;
render() {
// this.context.i13n.getI13nNode() to access the nearest i13nNode created by createI13nNode
// this.context.i13n.executeEvent() to execute i13n event
Expand Down
11 changes: 7 additions & 4 deletions index.es.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/

import I13nNodeLib from './dist-es/libs/I13nNode';
import ReactI13nLib from './dist-es/libs/ReactI13n';
import I13nNodeLib from './dist-es/core/I13nNode';
import ReactI13nLib, { getInstance as getInstanceLib } from './dist-es/core/ReactI13n';

import createI13nNodeLib from './dist-es/utils/createI13nNode';
import setupI13nLib from './dist-es/utils/setupI13n';
import createI13nNodeLib from './dist-es/core/createI13nNode';
import setupI13nLib from './dist-es/core/setupI13n';

import I13nAnchorLib from './dist-es/components/I13nAnchor';
import I13nButtonLib from './dist-es/components/I13nButton';
import I13nContextLib from './dist-es/components/core/I13nContext';
import I13nDivLib from './dist-es/components/I13nDiv';

// Core libraries
export var I13nNode = I13nNodeLib;
export var ReactI13n = ReactI13nLib;
export var getInstance = getInstanceLib;

// Utils
export var createI13nNode = createI13nNodeLib;
Expand All @@ -24,3 +26,4 @@ export var setupI13n = setupI13nLib;
export var I13nAnchor = I13nAnchorLib;
export var I13nButton = I13nButtonLib;
export var I13nDiv = I13nDivLib;
export var I13nContext = I13nContextLib;
12 changes: 6 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@

module.exports = {
// Core libraries
I13nNode: require('./dist/libs/I13nNode').default,
ReactI13n: require('./dist/libs/ReactI13n').default,

// Utils
createI13nNode: require('./dist/utils/createI13nNode').default,
setupI13n: require('./dist/utils/setupI13n').default,
createI13nNode: require('./dist/core/createI13nNode').default,
getInstance: require('./dist/core/ReactI13n').getInstance,
I13nNode: require('./dist/core/I13nNode').default,
ReactI13n: require('./dist/core/ReactI13n').default,
setupI13n: require('./dist/core/setupI13n').default,

// I13n Components
I13nAnchor: require('./dist/components/I13nAnchor').default,
I13nButton: require('./dist/components/I13nButton').default,
I13nContext: require('./dist/components/core/I13nContext').default,
I13nDiv: require('./dist/components/I13nDiv').default
};
2 changes: 2 additions & 0 deletions jest-setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// polyfill
require('intersection-observer');
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
module.exports = {
setupFilesAfterEnv: ['./jest-setup.js'],
reporters: ['default', 'jest-junit']
};
19 changes: 12 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "react-i13n",
"description": "React I13n provides a performant and scalable solution to application instrumentation.",
"version": "3.0.0-alpha.4",
"version": "3.0.0-alpha.5",
"main": "index.js",
"module": "index.es.js",
"repository": {
Expand All @@ -20,19 +20,23 @@
"func-debug": "npm run dist && npm run dist-functional && grunt functional-debug",
"lint": "eslint src",
"prepublish": "npm run dist",
"test": "jest tests/unit --coverage --coverageReporters=lcov",
"unit": "jest tests/unit"
"test": "jest src --coverage --coverageReporters=lcov",
"unit": "jest src"
},
"dependencies": {
"debug": "^4.1.1",
"hoist-non-react-statics": "^3.3.0",
"prop-types": "^15.7.2",
"react-in-viewport": "^1.0.0-alpha.16",
"subscribe-ui-event": "^2.0.5"
},
"devDependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.9.6",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.1",
"@babel/plugin-proposal-object-rest-spread": "^7.10.1",
"@babel/plugin-proposal-optional-chaining": "^7.10.1",
"@babel/plugin-transform-spread": "^7.8.3",
"@babel/preset-env": "^7.9.6",
"@babel/preset-react": "^7.9.4",
Expand All @@ -59,6 +63,7 @@
"grunt-contrib-watch": "^1.1.0",
"grunt-saucelabs": "^9.0.0",
"grunt-webpack": "^3.1.3",
"intersection-observer": "^0.12.0",
"jest": "^26.0.1",
"jest-junit": "^12.0.0",
"minimist": "^1.2.0",
Expand All @@ -67,8 +72,8 @@
"pre-commit": "^1.0.0",
"prettier": "^2.0.5",
"promise": "^8.0.2",
"react": "^16.8.3",
"react-dom": "^16.8.3",
"react": "^16.8.3 || ^17.0.0",
"react-dom": "^16.8.3 || ^17.0.0",
"webpack": "^4.0.0",
"webpack-dev-server": "^3.2.1",
"xunit-file": "^1.0.0"
Expand All @@ -80,8 +85,8 @@
"instrumentation"
],
"peerDependencies": {
"react": "^16.8.0",
"react-dom": "^16.8.0"
"react": "^16.8.0 || ^17.0.0",
"react-dom": "^16.8.0 || ^17.0.0"
},
"precommit": [
"lint",
Expand Down
2 changes: 1 addition & 1 deletion src/components/I13nAnchor.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/

import createI13nNode from '../utils/createI13nNode';
import createI13nNode from '../core/createI13nNode';

const I13nAnchor = createI13nNode('a', {
isLeafNode: true,
Expand Down
2 changes: 1 addition & 1 deletion src/components/I13nButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/

import createI13nNode from '../utils/createI13nNode';
import createI13nNode from '../core/createI13nNode';

const I13nButton = createI13nNode('button', {
isLeafNode: true,
Expand Down
2 changes: 1 addition & 1 deletion src/components/I13nDiv.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/

import createI13nNode from '../utils/createI13nNode';
import createI13nNode from '../core/createI13nNode';

const I13nDiv = createI13nNode('div', {
isLeafNode: false,
Expand Down
Loading

0 comments on commit 01106be

Please sign in to comment.