forked from vasanthk/react-bits
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path01.pure-render-checks.jsx
136 lines (117 loc) · 3.69 KB
/
01.pure-render-checks.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
134
135
136
/**
* Pure Render Checks
*
* In order to preserve performance one needs to consider the creation of new entities in the render method.
*
* Pure render?
* With React.js pure render I mean components that implement the shouldComponentUpdate method with shallow equality checks.
* Examples of this are the React.PureComponent, PureRenderMixin, recompose/pure and many others.
*
* @Reference:
* https://medium.com/@esamatti/react-js-pure-render-performance-anti-pattern-fb88c101332f
* https://github.com/nfour/js-structures/blob/master/guides/react-anti-patterns.md#pure-render-immutability
*/
/**
* CASE 1
*/
// BAD
class Table extends PureComponent {
render() {
return (
<div>
{this.props.items.map(i =>
// The issue is with {this.props.options || []} - it caused all the cells to be re-rendered even for a single cell change.
// Why?
// You see the options array was passed deep down in the Cell elements. Normally this would not be an issue.
// The other Cell elements would not be re-rendered because they can do the cheap shallow equality check and
// skip the render entirely but in this case the options prop was null and the default array was used.
// As you should know the array literal is the same as new Array() which creates a new array instance.
// This completely destroyed every pure render optimization inside the Cell elements.
// In Javascript different instances have different identities and thus the shallow equality check always
// produces false and tells React to re-render the components.
<Cell data={i} options={this.props.options || []}/>
)}
</div>
);
}
}
// GOOD
const defaultval = []; // <--- The fix (defaultProps could also have been used).
class Table extends PureComponent {
render() {
return (
<div>
{this.props.items.map(i =>
<Cell data={i} options={this.props.options || defaultval}/>
)}
</div>
);
}
}
/**
* CASE 2
*
* Similar issue with using functions in render() as well
*/
// BAD
class App extends PureComponent {
render() {
return <MyInput
onChange={e => this.props.update(e.target.value)}/>;
}
}
// BAD - again
class App extends PureComponent {
update(e) {
this.props.update(e.target.value);
}
render() {
return <MyInput onChange={this.update.bind(this)}/>;
}
}
// ^^In both cases a new function is created with a new identity. Just like with the array literal.
// We need to bind the function early
// GOOD
class App extends PureComponent {
constructor(props) {
super(props);
this.update = this.update.bind(this);
}
update(e) {
this.props.update(e.target.value);
}
render() {
return <MyInput onChange={this.update}/>;
}
}
// BAD
class Component extends React.Component {
state = {clicked: false};
onClick() {
this.setState({clicked: true})
}
render() {
const options = this.props.options || {test: 1}; // Options object created each render if not set
return <Something
options={options}
onClick={this.onClick.bind(this)} // New function created each render
onTouchTap={(event) => this.onClick(event)} // New function & closure created each render
/>
}
}
// GOOD
class Component extends React.Component {
state = {clicked: false};
options = {test: 1};
onClick = () => {
this.setState({clicked: true})
};
render() {
const options = this.props.options || this.options; // Options object created once
return <Something
options={options}
onClick={this.onClick} // Function created once, bound once
onTouchTap={this.onClick} // Function created once, bound once
/>
}
}