-
Notifications
You must be signed in to change notification settings - Fork 404
/
12-component-refactor.html
150 lines (131 loc) · 3.87 KB
/
12-component-refactor.html
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<!doctype html>
<title>12 Component Refactor - React From Zero</title>
<script src="https://unpkg.com/react@16.4.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.4.0/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/create-react-class@15.6.3/create-react-class.js"></script>
<script src="https://unpkg.com/prop-types@15.6.1/prop-types.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<div id="app"></div>
<script type="text/babel">
// Refactoring is another thing that is nice with React
// First we'll talk about refactoring one component into another
// if we're lucky, we can just change the components implementation
// and don't need to change anything at the call-site
// We start with a component that renders records somehow
function ViewBefore(props) {
return (
<table>
<thead>
<tr>
<th>Room</th>
<th>People</th>
</tr>
</thead>
<tbody>
{props.rooms.map(function(room, k) {
return (
<tr key={k}>
<td>{room.name}</td>
<td>{room.people}</td>
</tr>
);
})}
</tbody>
</table>
);
}
// The component has a simple props-interface
ViewBefore.propTypes = {
rooms: PropTypes.arrayOf(PropTypes.shape({
name: PropTypes.string.isRequired,
people: PropTypes.number.isRequired
})).isRequired
}
// We switch out the implementation with something more complex
function ViewAfter(props) {
return (
<div>
{props.rooms.map(function(room, k) {
var barStyle = {
display: "inline-block",
background: "lightgrey",
width: room.people * 25
};
return (
<div key={k}>
{room.people > 0 ? (
<span style={barStyle}>{room.people} People</span>
) : (
<span>0 People</span>
)}
<span> in {room.name}</span>
</div>
);
})}
</div>
);
}
// We keep the props-interface the same
ViewAfter.propTypes = {
rooms: PropTypes.arrayOf(PropTypes.shape({
name: PropTypes.string.isRequired,
people: PropTypes.number.isRequired
})).isRequired
}
// We could also switch it with something more dynamic
var ViewDynamic = createReactClass({
// We still keep the props-interface the same
propTypes: {
rooms: PropTypes.arrayOf(PropTypes.shape({
name: PropTypes.string.isRequired,
people: PropTypes.number.isRequired
})).isRequired
},
getInitialState: function() {
return { currentRoom: 0 };
},
componentDidMount() {
var component = this;
var props = this.props;
this.interval = setInterval(function() {
var currentRoom =
component.state.currentRoom < props.rooms.length - 1
? component.state.currentRoom + 1
: 0;
component.setState({ currentRoom: currentRoom });
}, 1000);
},
componentWillUnmount() {
clearInterval(this.interval);
},
render: function() {
var room = this.props.rooms[this.state.currentRoom];
return (
<span style={{ color: this.state.color }}>
Room <b>{room.name}</b> has <b>{room.people}</b> People.
</span>
);
}
});
// Some data
var rooms = [
{ name: "Office", people: 10 },
{ name: "Kitchen", people: 15 },
{ name: "Floor", people: 3 },
{ name: "Bathroom", people: 0 }
];
// As we can see the components can be used exactly the same
// If we copy the implementation of ViewAfter into ViewBefore,
// everything keeps working
var reactElement = (
<div style={{ margin: "auto", width: 500 }}>
<h3>Before the refactor</h3>
<ViewBefore rooms={rooms} />
<h3>After the refactor</h3>
<ViewAfter rooms={rooms} />
<h3>Dynamic refactor</h3>
<ViewDynamic rooms={rooms} />
</div>
);
ReactDOM.render(reactElement, document.getElementById("app"));
</script>