render
methods) during the update process. The second is the actual update of the page fragments by modifying the DOM. When I talk about “rendering” in this article, I mean the first option. class App extends Component { // ... render() { return ( <div> {/* 1. " DOM" */} <button onClick={() => { this.setState({ clicked: true }) }} > Click! </button> {/* 2. " " "" */} <Sidebar onToggle={(isOpen) => { this.setState({ sidebarIsOpen: isOpen }) }}/> {/* 3. render */} <Route path="/topic/:id" render={({ match }) => ( <div> <h1>{match.params.id}</h1>} </div> ) /> </div> ) } }
gzip
, which really strengthened this idea in me. He talked about an experiment that he did with LABjs
, the old library for loading scripts. You can watch this performance . What I’m talking about here takes about two and a half minutes, starting with the 30th minute of the video.obj.foo
), it used to store keys in strings and use square brackets to access the contents of objects ( obj[stringForFoo]
). The reason for this was that after minifying and compressing code with gzip
unusually written code would have to become less than code that was written in a familiar way.shouldComponentUpdate
. Let's sort out these concerns.bind
command was often used, this, historically, led to poor performance. For example: <div> {stuff.map(function(thing) { <div>{thing.whatever}</div> }.bind(this)} </div>
Function.prototype.bind
were corrected here , and the switch functions were either used as built-in features of the language, or transpiled with the help of babel into normal functions. And so and so we can assume that they are not slow. class Dashboard extends Component { state = { handlingThings: false } constructor(props) { super(props) this.handleThings = () => this.setState({ handlingThings: true }) this.handleStuff = () => { /* ... */ } // bind this.handleMoreStuff = this.handleMoreStuff.bind(this) } handleMoreStuff() { /* ... */ } render() { return ( <div> {this.state.handlingThings ? ( <div> <button onClick={this.handleStuff}/> <button onClick={this.handleMoreStuff}/> </div> ) : ( <button onClick={this.handleThings}/> )} </div> ) } }
render
need to create only one function. Instead, we create three. Moreover, no measurement of performance was not carried out, so we have no reason to consider this a problem.PureComponent
and shouldComponentUpdate
. In order to intelligently engage in performance optimization, you need to understand two things: the features of shouldComponentUpdate
, and how the comparison for strict equality works in JavaScript. Not understanding these concepts, you can, trying to make the code faster, only make things worse.setState
is setState
, React compares the old element with the new one (this is called reconciliation ) and then uses the resulting information to update the elements of the real DOM. Sometimes this operation can happen rather slowly if there are too many items to check (something like a large SVG). In such cases, React provides a workaround called shouldComponentUpdate
. class Avatar extends Component { shouldComponentUpdate(nextProps, nextState) { return stuffChanged(this, nextProps, nextState)) } render() { return //... } }
shouldComponentUpdate
, before React compares the old and the new elements, it will turn to shouldComponentUpdate
to find out if something has changed. If the response returns false
, React completely skips the element comparison operation, which saves some time. If the component is large enough, this can lead to a noticeable effect on performance.React.PureComponent
extension instead of React.Component
. PureComponent
will compare the properties and state in shouldComponentUpdate
, as a result, you will not have to do it yourself.class Avatar extends React.PureComponent { ... }
Avatar
class now uses strict equality comparisons when working with properties and state before requesting updates. It can be expected that this will speed up the program.string
, number
, boolean
, null
, undefined
, and symbol
. When you make a strict comparison of two variables of primitive types that store it the same value, it turns out to be true
. For example: const one = 1 const uno = 1 one === uno // true
PureComponent
compares properties, it uses strict comparison. This works great for embedded primitive values ​​like <Toggler isOpen={true}/>
.Object
. What about functions and arrays? In fact, all of these are objects. Let me quote an excerpt from the MDN documentation : “Functions are ordinary objects that have the additional ability to be called for execution.”false
. const one = { n: 1 } const uno = { n: 1 } one === uno // false one === one // true
PureComponent
will not be possible, resulting in a more time-consuming comparison of React elements. This comparison will only clarify that the component has not changed, as a result - the loss of time in the two comparisons. // <Avatar user={{ id: 'ryan' }}/> // <Avatar user={{ id: 'ryan' }}/> // , - , {} !== {} // () ,
PureComponent
performs a strict check on the equality of properties, the comparison of built-in functions when analyzing properties always ends with the message that they are different, after which the transition to the comparison of elements will be made during the matching procedure.shouldComponentUpdate
, when comparing identical functions, what we expect from it, it is necessary to preserve the referential identity of functions. For experienced JS developers, this is not such bad news. But, considering that Michael and I learned about 3,500 people after training, who have different levels of training, it can be noted that this task was not so easy for our students. It should be noted that the ES classes do not help here, so in this situation we have to use other JS features: class Dashboard extends Component { constructor(props) { super(props) // bind? , 20, // . // , . this.handleStuff = this.handleStuff.bind(this) // _this - . var _this = this this.handleStuff = function() { _this.setState({}) } // ES, , , // ( , babel ). // , - // . this.handleStuff = () => { this.setState({}) } } // , JavaScript, // , TC39 // . handleStuff = () => {} }
PureRenderMixin
(this is a design from earlier versions of React, which later became PureComponent
), I used many measurements and evaluated the performance of my application. Then I added a PureRenderMixin
to all components. When I took the measure of the performance of the optimized version, I hoped that as a result everything would be so wonderful that I could tell about it with pride.Component
, how many comparisons do you have to do when working with it? And what about PureComponent
? The answers, respectively, are as follows: "only one," and "at least one, and sometimes two." If the component usually changes during the update, PureComponent
will perform two comparison operations instead of one (the properties and state in shouldComponentUpdate
, and then the usual comparison of elements). This means that normally the PureComponen
t will be slower, but sometimes faster. Obviously, most of my components were constantly changing, so, in general, the application began to work more slowly. SadlyPureComponent
better to hold until you have measurements in order to evaluate the benefits of using this mechanism. <button onClick={() => this.setState(…)} >click</button>
setState
. This usually makes the built-in functions the most pure approach. Instead of jumping around the file looking for event handlers, you can find them in the item description code. The React community usually welcomes this.button
component (and any other DOM component) cannot even be a PureComponent
, so there’s no need to worry about shouldComponentUpdate
and the reference identity. <Sidebar onToggle={(isOpen) => { this.setState({ sidebarIsOpen: isOpen }) }}/>
Sidebar —
PureComponent
, we will not go PureComponent
property comparison. Again, since the handler is simple, embedding it may be the best solution.onToggle
, and why Sidebar
compares them. There are only two reasons for finding differences in properties in shouldComponentUpdate
:componentWillReceiveProps
, in componentDidUpdate
, or in componentWillUpdate
.on<whatever>
do not meet these requirements. Thus, most PureComponent
use PureComponent
lead to unnecessary comparisons, which forces developers to maintain, without need, the referential identity of the handlers.PureComponentMinusHandlers
class and inherit from it, instead of inheriting from PureComponent
. This will help to simply skip all feature checks. Just what you need. Well - almost what you need. // 1. . // 2. , // , . // 3. setState // ** . // 4. , // . // 5. // , // . class App extends React.Component { state = { val: "one" } componentDidMount() { this.setState({ val: "two" }) } render() { return <Form value={this.state.val} /> } } const Form = props => ( <Button onClick={() => { submit(props.value) }} /> ) class Button extends React.Component { shouldComponentUpdate() { // , , . return false } handleClick = () => this.props.onClick() render() { return ( <div> <button onClick={this.props.onClick}>This one is stale</button> <button onClick={() => this.props.onClick()}>This one works</button> <button onClick={this.handleClick}>This one works too</button> </div> ) } }
PureRenderWithoutHandlers
, do not pass your handlers, not participating in the comparison, directly to other components - they need to be wrapped in some way. <Route path="/topic/:id" render={({ match }) => ( <div> <h1>{match.params.id}</h1>} </div> ) />
render —
a template used to create a component that exists to create and maintain a shared state ( you can read more about this here ). The contents of the render
property are unknown to the component. For example: const App = (props) => ( <div> <h1>Welcome, {props.name}</h1> <Route path="/" render={() => ( <div> {/* props.name Route , Route PureComponent, , . */} <h1>Hey, {props.name}, let's get started!</h1> </div> )}/> </div> )
render
property will not lead to problems with shouldComponentUpdate
. , PureComponent
.render
. — , .PureComponent
and shouldComponentUpdate
only when necessary, skipping functions that are component properties (only if they are not used in life-cycle interceptor events to achieve side effects).Source: https://habr.com/ru/post/340034/
All Articles