UNPKG

3.36 kBMarkdownView Raw
1# React Side Effect
2Create components whose prop changes map to a global side effect.
3
4## Installation
5
6```
7npm install --save react-side-effect
8```
9
10## Use Cases
11
12* Setting `document.style.overflow` or background color depending on current screen;
13* Firing Flux actions using declarative API depending on current screen;
14* Some crazy stuff I haven't thought about.
15
16## How's That Different from `componentDidUpdate`?
17
18It gathers current props across *the whole tree* before passing them to side effect. For example, this allows you to create `<BodyStyle style>` component like this:
19
20```js
21// RootComponent.js
22return (
23 <BodyStyle style={{ backgroundColor: 'red' }}>
24 {this.state.something ? <SomeComponent /> : <OtherComponent />}
25 </BodyStyle>
26);
27
28// SomeComponent.js
29return (
30 <BodyStyle style={{ backgroundColor: this.state.color }}>
31 <div>Choose color: <input valueLink={this.linkState('color')} /></div>
32 </BodyStyle>
33);
34```
35
36and let the effect handler merge `style` from different level of nesting with innermost winning:
37
38```js
39var BodyStyle = createSideEffect(function handleChange(propsList) {
40 var style = {};
41 propsList.forEach(function (props) {
42 Object.assign(style, props.style);
43 });
44
45 for (var key in style) {
46 document.style[key] = style[key];
47 }
48});
49```
50
51
52## API
53
54#### `createSideEffect: (onChange: Array<Props> -> (), mixin: Object?) -> ReactComponent`
55
56Returns a component that, when mounting, unmounting or receiving new props, calls `onChange` with `props` of **each mounted instance**.
57It's up to you to `reduce` them, use innermost values, or whatever you fancy.
58
59Component will have a static `dispose()` method to clear the stack of mounted instances.
60When rendering on server, you must call it after each request.
61
62You can use optional second `mixin` parameter to specify `propTypes`, `displayName` or `statics`. It will be mixed into the generated component.
63
64## Usage
65
66Here's how to implement [React Document Title](https://github.com/gaearon/react-document-title) (both client and server side) using React Side Effect:
67
68```js
69'use strict';
70
71var React = require('react'),
72 createSideEffect = require('react-side-effect');
73
74/**
75 * Extract title from a list of each mounted component's props.
76 * We're interested in the innermost title, but for other use cases we might want to call `propList.reduce`.
77 */
78function extractTitle(propsList) {
79 var innermostProps = propsList[propsList.length - 1];
80 if (innermostProps) {
81 return innermostProps.title;
82 }
83}
84
85var _serverTitle = null;
86
87/**
88 * Generate a component that reacts to mounting, onmounting and prop changes by updating document title.
89 */
90var DocumentTitle = createSideEffect(function handleChange(propsList) {
91 var title = extractTitle(propsList);
92
93 if (typeof document !== 'undefined') {
94 document.title = title || '';
95 } else {
96 _serverTitle = title || null;
97 }
98}, {
99 displayName: 'DocumentTitle',
100
101 propTypes: {
102 title: React.PropTypes.string.isRequired
103 },
104
105 statics: {
106 /**
107 * Peek at current title (for tests).
108 */
109 peek: function () {
110 return _serverTitle;
111 },
112
113 /**
114 * Call this on server after each request to get current title.
115 */
116 rewind: function () {
117 var title = _serverTitle;
118 this.dispose();
119 return title;
120 }
121 }
122});
123
124module.exports = DocumentTitle;
125```