from 0 to 1 realization of React series--5.purecomponent realization && HOC Exploration

Source: Internet
Author: User
Tags diff


This series of articles helps to rationalize the core content of the React framework (jsx/Virtual dom/component/life cycle/diff algorithm/setstate/purecomponent/hoc/...) while implementing a Cpreact project address


    • Implement React series--JSX and Virtual DOM from 0 to 1
    • Implement React series from 0 to 1-components and State|props
    • 0 to 1 implementation of the React Series-Lifecycle and diff algorithms
    • Implementation of the React series from 0 to 1-optimized for setState and ref implementations
    • from 0 to 1 realization of React series--purecomponent realization && HOC Exploration
Purecomponent Essence


Using purecomponent is a common means of optimizing React performance, and Purecomponent automatically executes the shouldcomponentupdate () function once before render, compared to Component, based on the returned bool Value to determine whether to render. One of the main points is that purecomponent will be shallowequal (shallow comparison) at Shouldcomponentupdate ().



Purecomponent's shallow comparison strategy is as follows:



A shallow comparison of the two groups of data, Prevstate/nextstate and Prevprops/nextprops:



1. Object The first layer of data has not changed, the render method does not trigger;
2. Object first layer of data changes (including the first layer of data reference changes), the Render method will trigger;


The realization of purecomponent


According to the above-mentioned ideas, we can realize purecomponent logic


Function PureComponent(props) {
  This.props = props || {}
  This.state = {}

  isShouldComponentUpdate.call(this) // Bind the shouldComponentUpdate method for each PureComponent
}

PureComponent.prototype.setState = function(updater, cb) {
  isShouldComponentUpdate.call(this) // When calling setState , let this point to the instance of the subclass, and take the purpose of this.state of the subclass
  asyncRender(updater, this, cb)
}

Function isShouldComponentUpdate() {
  Const cpState = this.state
  Const cpProps = this.props
  this.shouldComponentUpdate = function (nextProps, nextState) {
    If (!shallowEqual(cpState, nextState) || !shallowEqual(cpProps, nextProps)) {
      Return true // render as long as state or props are less than equal
    } else {
      Return false // If the comparison is equal, no rendering
    }
  }
}

// shallow comparison logic
Const shallowEqual = function(oldState, nextState) {
  Const oldKeys = Object.keys(oldState)
  Const newKeys = Object.keys(nextState)

  If (oldKeys.length !== newKeys.length) {
    Return false
  }

  Let flag = true
  For (let i = 0; i < oldKeys.length; i++) {
    If (!nextState.hasOwnProperty(oldKeys[i])) {
      Flag = false
      Break
    }

    If (nextState[oldKeys[i]] !== oldState[oldKeys[i]]) {
      Flag = false
      Break
    }
  }

  Return flag
}
Test Cases


The test case is used in a issue case in React, and we expect to add 1 to the value displayed on the page after clicking the Add button.


class B extends PureComponent {
  constructor(props) {
    super(props)
    this.state = {
      count: 0
    }
    this.click = this.click.bind(this)
  }

  click() {
    this.setState({
      count: ++this.state.count,
    })
  }

  render() {
    return (
      <div>
        <button onClick={this.click}>增加</button>
        <div>{this.state.count}</div>
      </div>
    )
  }
}


However, we click on the above code, the page displayed on the 0 points no move!!!



The secret is as follows:


click() {
  const t = ++this.state.count
  console.log(t === this.state.count) // true
  this.setState({
    count: t,
  })
}


When the Add button is clicked, the console display is true, which indicates that the state of thet === this.state.countsetState is uniform, so shallowequal (shallow comparison) returns true, causing Shouldcomponentupdate to return false, the page is This does not render.



Similarly, the following wording is not up to the goal, left to the reader to think.


click() {
  this.setState({
    count: this.state.count++,
  })
}


So how do we achieve our desired goals? The secret is as follows:


click() {
  this.setState({
    count: this.state.count + 1
  })
}


Sentiment: A small line of code contains countless bugs.


The practice of HOC


Higher-order components (higher order Component) are not part of the React API category, but they are also a practical technique in React它可以将常见任务抽象成一个可重用的部分. This section is a foreign article, will be combined with Cpreact (previously implemented class react wheel) and the relevant practice of the HOC.



It can be expressed in the following formula:


y = f(x),

// x: original component
// y: high-level components
// f():


f()Implementation there are two methods, the following practice.


Property agent (Props proxy)


This kind of implementation is also an application of the adorner pattern, which can be assigned to the original function through the adorner function. The following example passes an additional property {a:1, b:2} to the decorated component in the adorner function.


Disclaimer: The demo shown below has been tested in Cpreact

function ppHOC(WrappedComponent) {
  return class extends Component {

    render() {
      const obj = { a: 1, b: 2 }
      return (
        <WrappedComponent { ...this.props } { ...obj } />
      )
    }
  }
}

@ppHOC
class B extends Component {
  render() {
    return (
      <div>
        { this.props.a + this.props.b } { /* 输出 3 */ }
      </div>
    )
  }
}


If you replace {a:1, b:2} with a global shared object, is it not Connect in React-redux?



To improve the above demo, we can implement pluggable controlled components, the code is as follows:


function ppDecorate(WrappedComponent) {
  return class extends Component {
    constructor() {
      super()
      this.state = {
        value: ''
      }
      this.onChange = this.onChange.bind(this)
    }

    onChange(e) {
      this.setState({
        value: e.target.value
      })
    }

    render() {
      const obj = {
        onChange: this.onChange,
        value: this.state.value,
      }

      return (
        <WrappedComponent { ...this.props } { ...obj } />
      )
    }
  }
}

@ppDecorate
class B extends Component {
  render() {
    return (
      <div>
        <input { ...this.props } />
        <div>{ this.props.value }</div>
      </div>
    )
  }
}


Effects such as:






There's a pit point, and when we enter a character in the input box, we don't immediately trigger the OnChange event (we want the event to trigger immediately, but now we have to press ENTER or click the mouse to trigger), there is a knowledge of the composition event in the react, and the next article explores.



Incidentally, in this demo seems to see the effect of two-way binding, but the actual React does not have a two-way binding concept, but we can use the knowledge point of the HOC setState in the React form to achieve the effect of pseudo-bidirectional binding.


Inheritance reversal (inheritance inversion)


The core of inheritance inversion is that the component passed into the HOC is used as the parent class of the return class. It is then called in Rendersuper.render()to invoke the parent class's Render method.


In the difference between ES6 inheritance and ES5 inheritance, we refer to the super point that is used as an object to the instance of the parent class.

Function iiHOC(WrappedComponent) {
   Return class extends WrappedComponent {
     Render() {
       Const parentRender = super.render()
       If (parentRender.nodeName === 'span') {
         Return (
           <span>Inheritance Inversion</span>
         )
       }
     }
   }
}

@iiHOC
Class B extends Component {
   Render() {
     Return (
       <span>Inheritance Inversion</span>
     )
   }
}  


In this demo, the implementation of the rendering hijacking within the HOC, the page is displayed as follows:




There may be doubts,属性代理the way you use it seems to be able to achieve the rendering hijacking, but that does not do that继承反转way purely.

Acknowledgement


Especially thank Simple-react for the guidance function of this library. At the Meantime,respect for Preact and react


RELATED LINKS
    • A doubt behaviour using the Purecomponent
    • React performance Optimization (i) When Purecomponent meets the Immutablejs
    • Purecomponent of React performance optimization scheme
    • With three questions. React Advanced Components
    • Deep understanding of React high-order components
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.