forked from kay-is/react-from-zero
-
Notifications
You must be signed in to change notification settings - Fork 5
/
13-element-refactor.html
107 lines (87 loc) · 3.14 KB
/
13-element-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
<!doctype html>
<title>13 Element Refactor - React From Zero</title>
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/[email protected]/create-react-class.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<div id="app"></div>
<script type="text/babel">
// Refactoring an element is a bit more tricky
// First, casing of JSX determines whether a tag is an element or a
// component
// lower case means element
// upper case means component
var element = <div />;
// becomes
element = React.createElement("div", null);
try {
var component = <Div />;
// becomes
component = React.createElement(Div, null);
} catch (e) {}
// Second, React converts all events these elements trigger, to
// synthetic events. This is often no problem, they are simply events.
// But we can't trigger our own. So even if our <Input> component
// accepts an onClick callback as property, we can't call it with the
// same event as an <input> element would.
// One approach could be this.
// We simply implement our own onChange caller
// Here we create a number input that only calls onChange on numbers
// (non-numbers trigger an empty change)
var NumberInput = createReactClass({
getInitialState: function() {
return { value: "" };
},
handleInput: function(e) {
// we could try to modify the event to get our data in
// but this could mess things up
// instead we prevent this event from further actions
e.preventDefault();
var newNumber = e.target.value;
// filter empty-changes
if (newNumber.length < 1 || newNumber === this.state.value)
return;
this.setState({ value: newNumber });
// then we extract our data and give it to onChange
this.props.onChange(newNumber);
},
render: function() {
return (
<input
type="number"
value={this.state.value}
onChange={this.handleInput}
/>
);
}
});
function logChange(v) {
console.log(v);
}
// Here we see, that the new NumberInput has a different interface
// it's onChange property implies that events will be received, but
// this isn't the case. Also, even if we would want to call it like
// the original input, we would need to use upper case, and wouldn't
// win anything.
var reactElement = (
<div style={{ width: 300, margin: "auto" }}>
<h2>Logging number inputs</h2>
<h2>Before Refactor</h2>
<input
type="number"
onChange={function(e) {
logChange(e.target.value);
}}
/>
<h2>After Refactor</h2>
<NumberInput onChange={logChange} />
</div>
);
ReactDOM.render(reactElement, document.getElementById("app"));
// Other approaches include not using "default" prop names in the
// first place onUpdate instead of onChange. It could also happen that
// a component uses onMouseDown to do something internal and triggers
// an onChange, which could cause confusion. Often components deliver
// richer interactions than elements in the first place so their prop
// methods can reflect that with the name
</script>