forked from kay-is/react-from-zero
-
Notifications
You must be signed in to change notification settings - Fork 0
/
13-element-refactor.html
104 lines (70 loc) · 2.9 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
<!doctype html>
<title>13 Element Refactor - React From Zero</title>
<script src="https://unpkg.com/[email protected]/dist/react.js"></script>
<script src="https://unpkg.com/[email protected]/dist/react-dom.js"></script>
<script src="https://unpkg.com/[email protected]/browser.min.js"></script>
<div id='app'></div>
<script type="text/babel">
// Refactoring an element is a bit more tricky
// First, React decides if a tag is an element by checking its case
// 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 not a problem, they are simply events.
// But you can't trigger your own.
// So even if your <Input> component accepts a onClick callback as property
// You 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 number inputs
// (non-numbers trigger an empty change)
var NumberInput = React.createClass({
getInitialState: function() {
return {value: ''}
},
handleInput: function(e) {
// we could try to modify the event to get or 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 that a component uses onMouseDown to do something internall
// and triggers a 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>