React. Js — Componentization of the front End (part 2) : Optimizing DOM operations

In this paper, the author: beard, in this paper, the original: huziketang.com/books/react…

Please indicate the source, keep the original link and author information

Online reading: huziketang.com/books/react…


To start with a simple example of our code, take a closer look at the changeLikeText function. This function contains the DOM operation, which looks simpler now because there is only one state, isLiked. Since data state changes can cause us to update the content of the page, imagine that if your component relies on a lot of state, then your component is basically all DOM manipulation.

It is very common for a component’s display morphology to be determined by multiple states. Intermixing DOM manipulation with code is actually a bad practice, and manually managing the relationship between data and DOM can make code less maintainable and error-prone. So there’s room for optimization in our example: How do you minimize this manual DOM manipulation?

State changes -> Build a new DOM element to update the page

One solution proposed here is to re-call the Render method as soon as the state changes and build a new DOM element. What are the benefits of this? The nice thing is that you can use the latest this.state in the Render method to construct different HTML structured strings, and construct different DOM elements from that string. The page is updated! If this sounds a bit convoluted, look at the code and change the original code to:

  class LikeButton {
    constructor () {
      this.state = { isLiked: false }
    }

    setState (state) {
      this.state = state
      this.el = this.render()
    }

    changeLikeText () {
      this.setState({
        isLiked:!this.state.isLiked
      })
    }

    render () {
      this.el = createDOMFromString(`
        <button class='like-btn'>
          <span class='like-text'>The ${this.state.isLiked ? 'cancel' : 'thumb up'}< / span > < span > 👍 < / span > < / button > `)
      this.el.addEventListener('click'.this.changeLikeText.bind(this), false)
      return this.el
    }
  }Copy the code

Just a few minor changes:

  1. renderThe HTML string inside the function is based onthis.stateDifferent but different (ES6 template strings are used here, which is handy for this kind of thing).
  2. A newsetStateFunction, which takes an object as an argument; It will set the instancestateAnd then call it againrenderMethods.
  3. When the user clicks the button,changeLikeTextWill build a newstateObject, this new onestateAnd the incomingsetStateDelta function.

As a result, every time the user clicks, changeLikeText calls change component state and then setState; SetState calls Render, and the Render method reconstructs different DOM elements based on the state.

That is, you just call setState and the component will be rerendered. We have successfully eliminated manual DOM manipulation.

Re-insert a new DOM element

The above improvements won’t work because if you look closely, you’ll notice that the DOM element being re-rendered is not actually inserted into the page. So outside of the component, you need to know that the component has changed and that the new DOM element has been updated to the page.

Modify the setState method:

. setState (state) {const oldEl = this.el
      this.state = state
      this.el = this.render()
      if (this.onStateChange) this.onStateChange(oldEl, this.el)
    }
...Copy the code

When using this component:

const likeButton = new LikeButton()
wrapper.appendChild(likeButton.render()) // Insert the DOM element for the first time
component.onStateChange = (oldEl, newEl) = > {
  wrapper.insertBefore(newEl, oldEl) // Insert a new element
  wrapper.removeChild(oldEl) // Delete the old element
}Copy the code

The onStateChange method is called every time setState is instantiated, so you can customize the behavior of onStateChange. So what we’re doing here is, every time we construct a new DOM element in setState, we’re going to tell the outside world to insert a new DOM element through onStateChange, and then delete the old one, and the page is updated. This has been further optimized: you no longer need to manually update the page.

Unusual violence, because each setState reconstructs, adds, and removes DOM elements, can cause a lot of browser reordering, which can seriously affect performance. No matter, such violence can be circumvented by a strategy called virtual-dom, but that is beyond the scope of this article.

This version has nice likes, and I can keep adding features to it without having to manually manipulate the DOM. But the downside is that if I were to create a new component, say a comment component, then I would have to rewrite all of these setState methods, and all of these things could be pulled out and turned into a generic pattern.

In the next section of the react.js book, Lesson4: front componentization: abstracting common component classes, we’ll separate this general pattern into a single class.