Files
react-from-zero/12-component-refactor.html
2018-09-26 15:35:37 +02:00

150 lines
3.9 KiB
HTML

<!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>