React source code

React source code

React source code

8.context

Example 8.1.

/* * @Author: dfh * @Date: 2021-02-24 18:18:22 * @LastEditors: dfh * @LastEditTime: 2021-03-01 13:25:37 * @Modified By: dfh * @FilePath: /day25-react/src/index.js */
import React from 'react';
import ReactDOM from 'react-dom';
const PersonContext = React.createContext();
function getStyle(color) {
  return {
    border: `5px solid ${color}`.padding: '5px'.marigin: '5px'}}class Person extends React.Component {
  state = {
    color: 'red'
  }

  changeColor = (color) = > this.setState({ color })

  render() {
    const value = { color: this.state.color, changeColor: this.changeColor }
    return <PersonContext.Provider value={value}>
      <div style={{ . getStyle(this.state.color), width: '200px' }}>
        Person
      <Head />
        <Body />
      </div>
    </PersonContext.Provider>}}class Head extends React.Component {
  static contextType = PersonContext;

  render() {
    return (
      <div style={getStyle(this.context.color)}>
        Head
        <Eye />
      </div>)}}class Body extends React.Component {
  static contextType = PersonContext;

  render() {
    return (
      <div style={getStyle(this.context.color)}>
        Body
        <Hand />
      </div>)}}class Hand extends React.Component {
  static contextType = PersonContext;

  render() {
    return (
      <div style={getStyle(this.context.color)}>
        Hand
        <button onClick={()= >Enclosing context. ChangeColor () 'red'} > to become red</button>
        <button onClick={()= >Enclosing context. ChangeColor (' green ')} > turn green</button>
      </div>)}}function Eye() {
  return <PersonContext.Consumer>
    {content => <div style={getStyle(content.color)}>Eye</div>}
  </PersonContext.Consumer>
}

ReactDOM.render(<Person />.document.getElementById('root'));
Copy the code

8.2. To achieve

8.2.1.src/react.js
/* * @Author: dfh * @Date: 2021-02-24 18:34:24 * @LastEditors: dfh * @LastEditTime: 2021-03-01 13:33:21 * @Modified By: dfh * @FilePath: /day25-react/src/react.js */
import Component from './Component';
import { wrapToVdom } from './utils';
/ * * * *@param {*} Type Element type *@param {*} Config Configures the object *@param {*} Children */
function createElement(type, config, children) {
    let ref, key;
    if (config) {
        delete config.__source;
        delete config.__self;
        ref = config.ref;
        key = config.key;
        delete config.ref;
        delete config.key;
    }
    letprops = { ... config };if (arguments.length > 3) {//children is an array
        props.children = Array.prototype.slice.call(arguments.2).map(wrapToVdom);
    } else {
        props.children = wrapToVdom(children);
    }
    return {
        type,
        props,
        ref,
        key
    }
}

function createRef() {
    return { current: null}} +function createContext(initialValue) {
+   Provider._value = initialValue;
+   function Provider(props) {+const { value } = props;
+       if (Provider._value) {
+           Object.assign(Provider._value, value)
+       } else{ + Provider._value = value; +},returnprops.children; +},function Consumer(props) {+returnprops.children(Provider._value); +},return{ Provider, Consumer }; +}const React = {
    createElement,
    Component,
    createRef,
+   createContext
}
export default React;
Copy the code
8.2.2.src/react-dom.js
/* * @Author: dfh * @Date: 2021-02-24 18:34:32 * @LastEditors: dfh * @LastEditTime: 2021-03-01 13:40:33 * @Modified By: dfh * @FilePath: /day25-react/src/react-dom.js */

import { REACT_TEXT } from './constants';
import { addEvent } from './event';

/** * when the container is mounted@param {*} Vdom requires the rendering of the virtual DOM *@param {*} The container vessel * /
function render(vdom, container) {
    const dom = createDOM(vdom);
    // Mount the real DOM
    container.appendChild(dom);
    // Call the lifecycle method componentDidMount
    dom.componentDidMount && dom.componentDidMount();
}

/** * create validation DOM *@param {*} Vdom Virtual DOM */
export function createDOM(vdom) {
    const {
        type,
        props,
        key,
        ref
    } = vdom;
    // Create the real DOM
    let dom;
    if (type === REACT_TEXT) {/ / is the text
        dom = document.createTextNode(props.content);
    } else if (typeof type === 'function') {// Custom function components
        if (type.isReactComponent) {/ / class components
            return mountClassComponent(vdom);
        } else {// Function components
            returnmountFunctionComponent(vdom); }}else {// Native components
        dom = document.createElement(type);
    }

    // Update the properties of the newly created real DOM with the properties of the virtual DOM
    updateProps(dom, {}, props);
    if (typeof props.children === 'object' && props.children.type) {// There is only one son, and it is a virtual DOM
        render(props.children, dom);// Turn the son into a real DOM and mount it on your own
    } else if (Array.isArray(props.children)) {// Have multiple sons
        reconcileChildren(props.children, dom);
    }

    // Mount the real DOM to the virtual DOM for later retrieval
    vdom.dom = dom;
    // After the real DOM is created from the virtual DOM, the current property of the ref property of the virtual DOM is equal to the real DOM
    ref && (ref.current = dom);
    return dom;
}

/** * Converts a virtual DOM of type custom class component into a real DOM and returns *@param {*} The vDOM type is the virtual DOM */ of the custom class component
function mountClassComponent(vdom) {
    const { type: Clazz, props } = vdom;
    // Get an instance of the class
    const classInstance = new Clazz(props);
  	/ / the implementation of the context
+   if(Clazz.contextType) { + classInstance.context = Clazz.contextType.Provider._value; +}// Make the classInstance property of the virtual DOM of this class component point to an instance of this class component
    vdom.classInstance = classInstance;
    // Call the lifecycle method componentWillMount
    if (classInstance.componentWillMount) {
        classInstance.componentWillMount();
    }
    // Execute the lifecycle method getDerivedStateFromProps
    if (Clazz.getDerivedStateFromProps) {
        const partialState = Clazz.getDerivedStateFromProps(classInstance.props, classInstance.state)
        if(partialState) { classInstance.state = { ... classInstance.state, ... partialState }; }}// Get the virtual DOM
    const oldRenderVdom = classInstance.render();
    // Mount the virtual DOM to the component instance for later dom-diff use
    classInstance.oldRenderVdom = vdom.oldRenderVdom = oldRenderVdom;
    // Get the real DOM
    const dom = createDOM(oldRenderVdom);

    if (classInstance.componentDidMount) {
        dom.componentDidMount = classInstance.componentDidMount;
    }
    // Attach the real DOM to the instance
    classInstance.dom = dom;

    return dom;
}

/** * Converts a virtual DOM of type custom function component into a real DOM and returns *@param {*} The vDOM type is the virtual DOM */ of the custom function component
function mountFunctionComponent(vdom) {
    const { type: FunctionComponent, props } = vdom;
    const renderVdom = FunctionComponent(props);
    vdom.oldRenderVdom = renderVdom;
    return createDOM(renderVdom);
}

/ * * * *@param {*} The virtual DOM for the childrenVdom@param {*} ParentDOM The real DOM to mount to */
function reconcileChildren(childrenVdom, parentDOM) {
    for (let i = 0; i < childrenVdom.length; i++) {
        const child = childrenVdom[i];
        render(child, parentDOM);// My son is attached to my body}}/** * Update the properties of the newly created real DOM with the properties of the virtual DOM *@param {*} Dom Real DOM *@param {*} The props virtual DOM attribute */
function updateProps(dom, oldProps, props) {
    for (const key in props) {
        if (key === 'children') continue;// Handle it separately, not here
        if (key === 'style') {
            const styleObj = props.style;
            for (const attr instyleObj) { dom.style[attr] = styleObj[attr]; }}else if (key.startsWith('on')) {//onClick=>onclick
            // dom[key.toLocaleLowerCase()]=props[key];
            addEvent(dom, key.toLocaleLowerCase(), props[key]);
        } else {// Class is defined in JS using className, so do not change itdom[key] = props[key]; }}}/** * Dom-diff * for the current component@param {*} ParentDOM is the real DOM *@param {*} OldRenderVdom is the old virtual DOM *@param {*} NewRenderVdom New virtual DOM *@param {*} NextDom Is the next real DOM, mainly used to insert the location with */
export function compareTwoVdom(parentDOM, oldRenderVdom, newRenderVdom, nextDom) {
    if(! oldRenderVdom && ! newRenderVdom) {// Both new and old virtual DOM are null
        return null;
    } else if(oldRenderVdom && ! newRenderVdom) {// The new virtual DOM is NULL, so the old DOM exists
        const currentDOM = findDOM(oldRenderVdom);// Find the real DOM corresponding to this virtual DOM
        currentDOM && parentDOM.removeChild(currentDOM);// Remove this old real DOM
        // Call the lifecycle method
        oldRenderVdom.classInstance && oldRenderVdom.classInstance.componentWillUnmount && oldRenderVdom.classInstance.componentWillUnmount()
    } else if(! oldRenderVdom && newRenderVdom) {// New virtual DOM exists, old virtual DOM is NULL
        const newDOM = createDOM(newRenderVdom);// Get the real DOM
        if (nextDom) {
            parentDOM.insertBefore(newDOM, nextDom);
        } else{ parentDOM.appendChild(newDOM); }}else if(oldRenderVdom && newRenderVdom && oldRenderVdom.type ! == newRenderVdom.type) {// Both the old and new virtual DOM exist, but of different types
        const oldDOM = findDOM(oldRenderVdom);// Old real DOM
        const newDOM = createDOM(newRenderVdom);// The new real DOM
        parentDOM.replaceChild(newDOM, oldDOM);
        // Call the lifecycle method
        oldRenderVdom.classInstance && oldRenderVdom.classInstance.componentWillUnmount && oldRenderVdom.classInstance.componentWillUnmount()
    } else {// Both old and new, the same type, to do deep DOM-diffupdateElement(oldRenderVdom, newRenderVdom); }}/** * In depth compare two virtual DOM *@param {*} OldRenderVdom is the old virtual DOM *@param {*} NewRenderVdom New virtual DOM */
function updateElement(oldRenderVdom, newRenderVdom) {
    if (oldRenderVdom.type === REACT_TEXT) {/ / text
        const currentDOM = newRenderVdom.dom = oldRenderVdom.dom;// Reuse old real DOM nodes
        currentDOM.textContent = newRenderVdom.props.content;// Modify the old DOM node files directly
    } else if (typeof oldRenderVdom.type === 'string') {// The specification is a native component
        const currentDOM = newRenderVdom.dom = oldRenderVdom.dom;// Reuse old real DOM
        // Update the attributes first
        updateProps(currentDOM, oldRenderVdom.props, newRenderVdom.props);
        // Compare sons
        updateChildren(currentDOM, oldRenderVdom.props.children, newRenderVdom.props.children);
    } else if (typeof oldRenderVdom.type === 'function') {
        if (oldRenderVdom.type.isReactComponent) {
            updateClassComponent(oldRenderVdom, newRenderVdom);// Update the class component
        } else {
            updateFunctionComponent(oldRenderVdom, newRenderVdom);// New and old are function components, function component update}}}/** * If the old virtual DOM node and the new virtual DOM node are functions, use this update logic *@param {*} OldVdom is the old virtual DOM *@param {*} NewVdom New virtual DOM */
function updateFunctionComponent(oldVdom, newVdom) {
    const parentDOM = findDOM(oldVdom).parentNode;// Find the old parent node
    const { type: FunctionComponent, props } = newVdom;
    const oldRenderVdom = oldVdom.oldRenderVdom;// Old render virtual DOM
    const newRenderVdom = FunctionComponent(props);// New render virtual DOM
    compareTwoVdom(parentDOM, oldRenderVdom, newRenderVdom);// Compare the virtual DOM
    newVdom.oldRenderVdom = newRenderVdom;
}

/** * If the old virtual DOM node and the new virtual DOM node are class components, use this update logic *@param {*} OldVdom is the old virtual DOM *@param {*} NewVdom New virtual DOM */
function updateClassComponent(oldVdom, newVdom) {
    const classInstance = newVdom.classInstance = oldVdom.classInstance;// Reuse old class instances
    newVdom.oldRenderVdom = oldVdom.oldRenderVdom;// The last class component's rendering of the virtual DOM
    if (classInstance.componentWillReceiveProps) {// The component will receive a new attribute
        classInstance.componentWillReceiveProps();
    }
    // Trigger an update to the component, passing in the new property
    classInstance.updater.emitUpdate(newVdom.props);
}
/** * In depth compare children *@param {*} DOM parentDOM father *@param {*} OldChildren have old sons@param {*} NewChildren New sons */
function updateChildren(parentDOM, oldChildren, newChildren) {
    // Children can be arrays or objects (single nodes are objects)
    oldChildren = Array.isArray(oldChildren) ? oldChildren : [oldChildren];
    newChildren = Array.isArray(newChildren) ? newChildren : [newChildren];
    // Get the maximum length
    const maxLen = Math.max(oldChildren.length, newChildren.length);
    for (let i = 0; i < maxLen; i++) {
        // Find the index greater than the current index in the sons
        const nextDOM = oldChildren.find((item, index) = > index > i && item && item.dom)
        // Compare children recursivelycompareTwoVdom(parentDOM, oldChildren[i], newChildren[i], nextDOM && nextDOM.dom); }}/** * Find the real DOM of this virtual DOM object@param {*} vdom 
 */
export function findDOM(vdom) {
    const { type } = vdom;
    let dom;
    if (typeof type === 'function') {
        dom = findDOM(vdom.oldRenderVdom)
    } else {
        dom = vdom.dom;
    }
    return dom
}

const ReactDOM = {
    render
}

export default ReactDOM;
Copy the code

9. Advanced components

9.1. The configuration

  • The installation
npm install react-app-rewired customize-cra @babel/plugin-proposal-decorators- D
Copy the code
  • package.json
  "scripts": {
    "start": "react-app-rewired start"."build": "react-app-rewired build"."test": "react-app-rewired test"."eject": "react-app-rewired eject"
  }
Copy the code
  • config-overrides.js
const {override,addBabelPlugin}=require('customize-cra');
module.exports=override(
	addBabelPlugin([
    '@babel/plugin-proposal-decorators', {'legacy':true}]))Copy the code
  • jsconfig.json
{
  'compilerOptions': {'experimentalDecorators':true}}Copy the code

9.2. Arguably

9.2.1. Property proxy
/* * @Author: dfh * @Date: 2021-02-24 18:18:22 * @LastEditors: dfh * @LastEditTime: 2021-03-01 15:25:38 * @Modified By: dfh * @FilePath: /day25-react/src/index.js */
import React from 'react';
import ReactDOM from 'react-dom';
/** * Advanced components have three application scenarios * 1. Property proxy */
const widthLoading = msg= > OldComponent= > {
  return class extends React.Component {
    show = () = > {
      const div = document.createElement('div')
      div.setAttribute('id'.'load');
      div.innerHTML = ` <p style="position:absolute; top:50%; left:50%; z-index:10; background-color:gray">${msg}</p>
      `
      document.body.appendChild(div);
    }

    hide = () = > {
      document.getElementById('load').remove();
    }
    render() {
      return <OldComponent show={this.show} hide={this.hide} />
    }
  }
}

@widthLoading('Loading... ')
class Hello extends React.Component {
  render() {
    return <div>
      <p>hello</p>
      <button onClick={this.props.show}>According to</button>
      <button onClick={this.props.hide}>hidden</button>
    </div>
  }
}
ReactDOM.render(<Hello />.document.getElementById('root'));
Copy the code
9.2.2. Reverse inheritance

Existing components can be extended based on reverse inheritance

  • src/index.js
/* * @Author: dfh * @Date: 2021-02-24 18:18:22 * @LastEditors: dfh * @LastEditTime: 2021-03-01 17:21:34 * @Modified By: dfh * @FilePath: /day25-react/src/index.js */ import React from './react'; import ReactDOM from './react-dom'; /** * Advanced components have three application scenarios * 1. Property broker * 2. */ class extends React.Component {state = {name: } componentWillMount() {console.log('button componentWillMount'); } componentDidMount() { console.log('button componentDidMount') } render() { return (<button name={this.state.name} title={this.props.title}></button>) } } const wrapper = Button => { return class extends Button { state = { number: 0 } componentWillMount() { console.log('WrapperButton componentWillMount'); } componentDidMount() { console.log('WrapperButton componentDidMount'); } handlerClick = () => { this.setState({ number: this.state.number + 1 }); } render() { const renderElement = super.render(); const newProps = { ... renderElement.props, ... this.state, onClick: this.handlerClick } return React.cloneElement(renderElement, newProps, this.state.number); }}} const WrapperButton = wrapper(Button) reactdom.render (<WrapperButton title=' title '/>, document.getElementById('root'));Copy the code
  • src/react.js
/* * @Author: dfh * @Date: 2021-02-24 18:34:24 * @LastEditors: dfh * @LastEditTime: 2021-03-01 17:21:21 * @Modified By: dfh * @FilePath: /day25-react/src/react.js */
import Component from './Component';
import { wrapToVdom } from './utils';
/ * * * *@param {*} Type Element type *@param {*} Config Configures the object *@param {*} Children */
function createElement(type, config, children) {
    let ref, key;
    if (config) {
        delete config.__source;
        delete config.__self;
        ref = config.ref;
        key = config.key;
        delete config.ref;
        delete config.key;
    }
    letprops = { ... config };if (arguments.length > 3) {//children is an array
        props.children = Array.prototype.slice.call(arguments.2).map(wrapToVdom);
    } else {
        props.children = wrapToVdom(children);
    }
    return {
        type,
        props,
        ref,
        key
    }
}

function createRef() {
    return { current: null}}function createContext(initialValue) {
    Provider._value = initialValue;
    function Provider(props) {
        const { value } = props;
        if (Provider._value) {
            Object.assign(Provider._value, value)
        } else {
            Provider._value = value;
        }
        return props.children;
    }
    function Consumer(props) {
        return props.children(Provider._value);
    }
    return { Provider, Consumer };
}

+ function cloneElement(oldElement, newProps, ... newChildren) {+let children = oldElement.props.children;
+   // Children may be undefined, object, array
+   if (children) {
+       if (!Array.isArray(children)) {// is an object
+           children = [children]
+       }
+   } else {//undefined+ children = []; + } + children.push(... newChildren); + children = children.map(wrapToVdom); +if (children.length === 0) {
+       children = undefined; +}else if (children.length === 1) {
+       children = children[0];
+   }
+   newProps.children = children;
+   constprops = { ... oldElement.props, ... newProps }; +return{... oldElement, props }; +}const React = {
    createElement,
    Component,
    createRef,
    createContext,
+   cloneElement
}
export default React;
Copy the code

10.render props

  • render propsIs the value of one inreactBetween components that use a value of functionpropsSimple techniques for sharing code
  • withrender propsThe component takes a function that returns areactElement and call it instead of implementing your own rendering logic
  • render propsIs a function that tells the component what to renderprops

10.1. Native implementation

/* * @Author: dfh * @Date: 2021-02-24 18:18:22 * @LastEditors: dfh * @LastEditTime: 2021-03-01 19:06:45 * @Modified By: dfh * @FilePath: /day25-react/src/index.js */ import React from 'react'; import ReactDOM from 'react-dom'; class MouseTracker extends React.Component { constructor(props) { super(props); this.state = { x: 0, y: 0 }; } handeMouseMove = event => { this.setState({ x: event.clientX, y: Event.clienty})} render() {return <div onMouseMove={this.handemousemove}> <h1> ({this.state.x},{this.state.y})</p> </div> } } ReactDOM.render(<MouseTracker />, document.getElementById('root'));Copy the code

10.2 render properties

/* * @Author: dfh * @Date: 2021-02-24 18:18:22 * @LastEditors: dfh * @LastEditTime: 2021-03-01 19:17:45 * @Modified By: dfh * @FilePath: /day25-react/src/index.js */ import React from 'react'; import ReactDOM from 'react-dom'; Class MouseTracker extends react.component.ponent {/** ** render props * 1. constructor(props) { super(props); this.state = { x: 0, y: 0 }; } handeMouseMove = event => { this.setState({ x: event.clientX, y: event.clientY }) } render() { return <div onMouseMove={this.handeMouseMove}> {this.props.render(this.state)} </div> } } <MouseTracker render={props => <> <h1> </h1> <p> ({props.x},{props.y})</p> </>} />, document.getElementById('root'));Copy the code

10.3. The children

Children is a rendering method

/*
 * @Author: dfh
 * @Date: 2021-02-24 18:18:22
 * @LastEditors: dfh
 * @LastEditTime: 2021-03-01 19:21:16
 * @Modified By: dfh
 * @FilePath: /day25-react/src/index-render-props1.js
 */
import React from 'react';
import ReactDOM from 'react-dom';

class MouseTracker extends React.Component {
  constructor(props) {
    super(props);
    this.state = { x: 0, y: 0 };
  }

  handeMouseMove = event => {
    this.setState({
      x: event.clientX,
      y: event.clientY
    })
  }

  render() {
    return <div onMouseMove={this.handeMouseMove}>
      {this.props.children(this.state)}
    </div>
  }
}
ReactDOM.render(<MouseTracker >{
  props => <>
    <h1>移动鼠标</h1>
    <p>当前的鼠标位置是:({props.x},{props.y})</p>
  </>
}</MouseTracker>, document.getElementById('root'));
Copy the code

10.4. Hoc

/* * @Author: dfh * @Date: 2021-02-24 18:18:22 * @LastEditors: dfh * @LastEditTime: 2021-03-01 19:35:21 * @Modified By: dfh * @FilePath: /day25-react/src/index.js */ import React from 'react'; import ReactDOM from 'react-dom'; function widthTracker(OldComponent) { return class MouseTracker extends React.Component { constructor(props) { super(props); this.state = { x: 0, y: 0 }; } handeMouseMove = event => { this.setState({ x: event.clientX, y: event.clientY }) } render() { return <div onMouseMove={this.handeMouseMove}> <OldComponent {... This. State} /> </div>}} function Show(props) {return <> <h1> mouse </h1> <p> ({props.x},{props.y})</p> </> } const MouseTracker = widthTracker(Show); ReactDOM.render(<MouseTracker />, document.getElementById('root'));Copy the code

11.shouldComponentUpdate

  • When a componentpropsorstateChange,ReactThe newly returned element is compared to the previously rendered element to determine if it is necessary to update the real DOM when they are not identicalReactThe DOM will be updated
  • If there are a lot of components to render, you can override the lifecycle methodshouldComponentUpdateTo optimize
  • shouldComponentUpdateMethod fires before rerendering. The default implementation is to return true. If the component does not need to be updated, it can be updated in theshouldComponentUpdateTo skip the entire rendering process. Which contains the componentrenderCalls and subsequent operations.

11.1. Examples – Component

Problem: Whether you click on button in Number1 or butter in Number2, all render is executed

/* * @Author: dfh * @Date: 2021-02-24 18:18:22 * @LastEditors: dfh * @LastEditTime: 2021-03-01 19:41:39 * @Modified By: dfh * @FilePath: /day25-react/src/index.js */ import React from 'react'; import ReactDOM from 'react-dom'; /** * By default, all components update whenever state changes, regardless of property changes */ class Counter extends React.Component {state = {num1:0, num2: 0 } addNum1 = () => { this.setState({ num1: this.state.num1 + 1 }) } addNum2 = () => { this.setState({ num2: this.state.num2 + 1 }) } render() { console.log('render Counter') return <div> <Number1 num={this.state.num1} add={this.addNum1} /> <Number2 num={this.state.num2} add={this.addNum2} /> </div> } } class Number1 extends React.Component { render() { console.log('render Number1') return <div> <button onClick={this.props.add}>Number1:{this.props.num}</button> </div> } } class Number2 extends React.Component { render() {  console.log('render Number2') return <div> <button onClick={this.props.add}>Number2:{this.props.num}</button> </div> } } ReactDOM.render(<Counter />, document.getElementById('root'));Copy the code

11.2. Examples – PuerComponent

When clicking on the button in Number1, only render Counter and render Number1 go, but when clicking on the button in Number2, only render Counter and render Number2 go

/* * @Author: dfh * @Date: 2021-02-24 18:18:22 * @LastEditors: dfh * @LastEditTime: 2021-03-01 19:46:48 * @Modified By: dfh * @FilePath: /day25-react/src/index.js */ import React from 'react'; import ReactDOM from 'react-dom'; class Counter extends React.Component { state = { num1: 0, num2: 0 } addNum1 = () => { this.setState({ num1: this.state.num1 + 1 }) } addNum2 = () => { this.setState({ num2: this.state.num2 + 1 }) } render() { console.log('render Counter') return <div> <Number1 num={this.state.num1} add={this.addNum1} /> <Number2 num={this.state.num2} add={this.addNum2} /> </div> } } class Number1 extends React.PureComponent { render() { console.log('render Number1') return <div> <button onClick={this.props.add}>Number1:{this.props.num}</button> </div> } } class Number2 extends React.PureComponent { render() { console.log('render Number2') return <div> <button onClick={this.props.add}>Number2:{this.props.num}</button>  </div> } } ReactDOM.render(<Counter />, document.getElementById('root'));Copy the code

11.3. PuerComponent implementation

/* * @Author: dfh * @Date: 2021-03-01 19:49:40 * @LastEditors: dfh * @LastEditTime: 2021-03-01 22:28:52 * @Modified By: dfh * @FilePath: /day25-react/src/PureComponent.js */
import Component from './Component';

class PureComponent extends Component {
    shouldComponentUpdate(nextProps, nextState) {
        constvalue=! shallowEqual(this.props, nextProps) || ! shallowEqual(this.state, nextState)
        console.log(value)
        returnvalue; }}/** * if obj1 is equal to obj2, it is equal if the memory address is the same@param {*} obj1 
 * @param {*} obj2 
 */
function shallowEqual(obj1, obj2) {
    if (obj1 === obj2) return true;
    if (typeofobj1 ! = ='object' || obj1 === null || typeofobj2 ! = ='object' || obj2 === null) return false;
    const key1 = Object.keys(obj1);
    const key2 = Object.keys(obj2);
    if(key1.length ! == key2.length)return false;
    for (let key of key1) {
        if(! obj2.hasOwnProperty(key) || obj1[key] ! == obj2[key])return false;
    }
    return true;
}

export default PureComponent;
Copy the code