Skip to content

Commit 8308684

Browse files
author
Daniel de la Cruz
committed
improved toggle propagation through child components via context
1 parent 4cfa437 commit 8308684

File tree

10 files changed

+145
-67
lines changed

10 files changed

+145
-67
lines changed

README.md

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,37 +29,52 @@ class MyComponent extends Component {
2929
}
3030
```
3131

32-
The component will receive a prop named `toggles` with an array of toggles, similar to this:
32+
The component will receive a prop named `toggles` with an array of toggles. You are free to implement any object pattern with the information needed to implement your toggle. This may be the simplest configuration possible to activate a simple toggle:
3333

3434
```javascript
3535
[{
3636
myToggle: true
37-
}, {
38-
myDisabledToggle: false
39-
}, {
40-
yetAnotherToggle: true
4137
}]
4238
```
4339

40+
Just keep in mind to be consistent when implementing the feature toggle in your component, and with the object you are sending in the array of toggles.
41+
4442
In the previous example, the component will only make use of `myToggle`... But how does it receive it? This is where `react-feature-toggles` is useful.
4543

46-
First, wrap your component into the higher order component `ReactToggle`:
44+
React Feature Toggles provides you two HOC: `ToggleApp` and `ToggleComponent`. Let's examine them in detail:
45+
46+
## ToggleComponent
47+
At the component level, just wrap your component into the higher order component `ToggleComponent`:
4748

4849
```javascript
49-
import { ReactToggle } from "../src";
50+
import { ToggleComponent } from 'react-feature-toggle';
5051
...
51-
export default ReactToggle(MyComponent);
52+
export default ToggleComponent(MyComponent);
5253
```
5354

54-
This will export your component as a _toggleable_ component.
55+
This will export your component as a _toggled_ component. What does it mean? Just that it will be wrapped with a Higher Order Component that will receive by context an array of toggles and pass it as props to your component.
56+
57+
Please notice that you only need to wrap your toggled component with the `ToggleComponent`, not the rest of your application's components, and the organic components using it neither. Please review the `docs` folder for a full example.
5558

56-
Secondly, the user of your component will need to provide the toggles somehow. It's up to you how to decide which toggles are activated or not, but you must provide the component a `promise` property with a `Promise` function that returns an array of feature toggles on being fullfilled:
59+
## ToggleApp
60+
At the top level of your application, you must wrap your app with the higher order component `ToggleApp`:
5761

5862
```javascript
59-
ReactDom.render(<MyComponent promise={
60-
new Promise(resolve => {
61-
resolve([{myToggle: true}]);
62-
})
63-
}
64-
/>, document.getElementById('main'));
63+
import { ToggleApp } from 'react-feature-toggle';
64+
...
65+
const MyToggledApp = ToggleApp(MyApp, toggles);
6566
```
67+
68+
The way to provide the array of toggles is up to you, but keep in mind that the user of your app will need to provide the toggles somehow. In the following example, I'm providing a `Promise` function that returns an array of feature toggles on being fullfilled:
69+
70+
```javascript
71+
new Promise(resolve => {
72+
resolve([{myToggle: false}]);
73+
})
74+
.then(toggles => {
75+
const MyToggledApp = ToggleApp(MyApp, toggles);
76+
ReactDom.render(<MyToggledApp />, document.getElementById('main'));
77+
});
78+
```
79+
80+
Please review the `docs` folder to get a complete example.

docs/index.jsx

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
/* eslint no-undef:0 */
2+
/* eslint new-cap:0 */
23
import 'babel-polyfill';
3-
import React from 'react';
4+
import React, { Component } from 'react';
45
import ReactDom from 'react-dom';
5-
import MyComponent from './myComponent';
6+
import MyComponentList from './myComponentList';
7+
import { ToggleApp } from '../src';
68

7-
ReactDom.render(<MyComponent promise={
8-
new Promise(resolve => {
9-
resolve([{myToggle: true}]);
10-
})
9+
class MyApp extends Component {
10+
constructor(...args){
11+
super(...args);
12+
}
13+
render() {
14+
return <MyComponentList />;
15+
}
1116
}
12-
/>, document.getElementById('main'));
17+
18+
new Promise(resolve => {
19+
resolve([{myToggle: false}]);
20+
})
21+
.then(toggles => {
22+
const MyToggledApp = ToggleApp(MyApp, toggles);
23+
ReactDom.render(<MyToggledApp />, document.getElementById('main'));
24+
});

docs/myComponent.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
/* eslint react/prop-types: 0 new-cap: 0 */
2-
import { ReactToggle } from '../src';
2+
import { ToggleComponent } from '../src';
33
import React, { Component } from 'react';
44

55
class MyComponent extends Component {
6+
constructor(...args){
7+
super(...args);
8+
}
69
render() {
7-
let myToggle = this.props.toggles.find(t => {
10+
let myToggle = this.props.toggles && this.props.toggles.find(t => {
811
let {myToggle} = t;
912
return myToggle;
1013
});
@@ -16,4 +19,4 @@ class MyComponent extends Component {
1619
}
1720
}
1821

19-
export default ReactToggle(MyComponent);
22+
export default ToggleComponent(MyComponent);

docs/myComponentList.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* eslint react/prop-types: 0 new-cap: 0 */
2+
import MyComponent from './myComponent';
3+
import React, { Component } from 'react';
4+
5+
class MyComponentList extends Component {
6+
constructor(...args){
7+
super(...args);
8+
}
9+
render() {
10+
return (<div>
11+
<MyComponent />
12+
<MyComponent />
13+
<MyComponent />
14+
<MyComponent />
15+
</div>);
16+
}
17+
}
18+
19+
export default MyComponentList;

package.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-feature-toggle",
3-
"version": "0.3.0",
3+
"version": "0.4.0",
44
"main": "lib/",
55
"scripts": {
66
"clean:lib": "rimraf ./lib/*",
@@ -15,8 +15,6 @@
1515
"lint": "npm run lint:eslint && npm run lint:sass",
1616
"lint:eslint": "eslint --ext=.js --ext=.jsx ./src/ ./test/ ./docs/",
1717
"lint:sass": "sass-lint src/**/*.scss -c -v",
18-
"test": "mocha --compilers js:babel-register --recursive --require babel-polyfill",
19-
"test:watch": "npm run test -- -w test src --watch-extensions jsx",
2018
"start": "npm run start:open && npm run start:server",
2119
"start:server": "webpack-dev-server",
2220
"start:open": "opener http://localhost:8080",
@@ -32,8 +30,7 @@
3230
"url": ""
3331
},
3432
"pre-commit": [
35-
"lint",
36-
"test"
33+
"lint"
3734
],
3835
"peerDependencies": {
3936
"react": "0.14"

src/index.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
import {ReactToggle} from './react-toggle';
2-
export {ReactToggle};
1+
import { ToggleApp } from './toggle-app';
2+
import { ToggleComponent } from './toggle-component';
3+
4+
export { ToggleApp, ToggleComponent };

src/react-toggle/index.jsx

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/toggle-app/index.jsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React, { Component, PropTypes } from 'react';
2+
3+
const ToggleApp = (ComposedApp, toggles) => class extends Component {
4+
constructor(...args){
5+
super(...args);
6+
}
7+
static get displayName() {
8+
const componentDisplayName =
9+
ComposedApp.name ||
10+
ComposedApp.displayName ||
11+
'App';
12+
13+
return `Toggled${componentDisplayName}`;
14+
}
15+
static get childContextTypes() {
16+
return {
17+
toggles: PropTypes.array
18+
};
19+
}
20+
getChildContext() {
21+
return {
22+
toggles: toggles
23+
};
24+
}
25+
render() {
26+
return <ComposedApp {...this.props} toggles={this.context.toggles} />;
27+
}
28+
};
29+
30+
export { ToggleApp };

src/toggle-component/index.jsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React, { Component, PropTypes } from 'react';
2+
3+
const ToggleComponent = ComposedComponent => class extends Component {
4+
static get childContextTypes() {
5+
return {
6+
toggles: PropTypes.array
7+
};
8+
}
9+
static get displayName() {
10+
const componentDisplayName =
11+
ComposedComponent.name ||
12+
ComposedComponent.displayName ||
13+
'Component';
14+
15+
return `Toggled${componentDisplayName}`;
16+
}
17+
static get contextTypes() {
18+
return {
19+
toggles: PropTypes.array
20+
};
21+
}
22+
getChildContext() {
23+
return this.toggles ? {
24+
toggles: this.toggles
25+
} : {
26+
toggles: [{ noToggles: true }]
27+
};
28+
}
29+
render() {
30+
return <ComposedComponent {...this.props} toggles={this.context.toggles} />;
31+
}
32+
};
33+
34+
export { ToggleComponent };

test/react-toggle-test.js

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)