forked from vasanthk/react-bits
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path25.presentational-vs-container.jsx
133 lines (107 loc) · 3.71 KB
/
25.presentational-vs-container.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
* Presentational and Container components
*
* Reference:
* https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.mbglcakmp
* https://github.com/krasimir/react-in-patterns/tree/master/patterns/presentational-and-container
* https://medium.com/@learnreact/container-components-c0e67432e005
*/
// PROBLEM
// Data and logic together.
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {time: this.props.time};
this._update = this._updateTime.bind(this);
}
render() {
var time = this._formatTime(this.state.time);
return (
<h1>{ time.hours } : { time.minutes } : { time.seconds }</h1>
);
}
componentDidMount() {
this._interval = setInterval(this._update, 1000);
}
componentWillUnmount() {
clearInterval(this._interval);
}
_formatTime(time) {
var [ hours, minutes, seconds ] = [
time.getHours(),
time.getMinutes(),
time.getSeconds()
].map(num => num < 10 ? '0' + num : num);
return {hours, minutes, seconds};
}
_updateTime() {
this.setState({time: new Date(this.state.time.getTime() + 1000)});
}
}
ReactDOM.render(<Clock time={ new Date() }/>, ...);
// SOLUTION
// Let's split the component into two parts - container and presentation.
// Container
// Containers know about data, it's shape and where it comes from. They know details about how the things work or the so called business logic.
// They receive information and format it so it is easy to use by the presentational component. Very often we use higher-order components to create containers.
// Their render method contains only the presentational component.
// Clock/index.js
import Clock from './Clock.jsx'; // <-- that's the presentational component
export default class ClockContainer extends React.Component {
constructor(props) {
super(props);
this.state = {time: props.time};
this._update = this._updateTime.bind(this);
}
render() {
return <Clock { ...this._extract(this.state.time) }/>;
}
componentDidMount() {
this._interval = setInterval(this._update, 1000);
}
componentWillUnmount() {
clearInterval(this._interval);
}
_extract(time) {
return {
hours: time.getHours(),
minutes: time.getMinutes(),
seconds: time.getSeconds()
};
}
_updateTime() {
this.setState({time: new Date(this.state.time.getTime() + 1000)});
}
};
// Presentational component
// Presentational components are concert with how the things look. They have the additional markup needed for making the page pretty.
// Such components are not bound to anything and have no dependencies.
// Very often implemented as a stateless functional components they don't have internal state.
// Clock/Clock.jsx
export default function Clock(props) {
var [ hours, minutes, seconds ] = [
props.hours,
props.minutes,
props.seconds
].map(num => num < 10 ? '0' + num : num);
return <h1>{ hours } : { minutes } : { seconds }</h1>;
};
// The nice things about containers is that they encapsulate logic and may inject data into different renderers.
// Very often a file that exports a container is not sending out a class directly but a function.
// For example, instead of using
import Clock from './Clock.jsx';
export default class ClockContainer extends React.Component {
render() {
return <Clock />;
}
}
// We may export a function that accepts the presentational component:
export default function (Component) {
return class Container extends React.Component {
render() {
return <Component />;
}
}
}
// Using this technique our container is really flexible in rendering its result.
// It will be really helpful if we want to switch from digital to analog clock representation.