Skip to content

9.子组件生命周期 ​

本节目标:理解“9.子组件生命周期”的核心思路,并能把它用于实际开发或面试表达。

说明:原 OneNote 中有图片引用,但图片未包含在导出目录中;本页保留了可用的文字与代码内容。 父子生命周期顺序

src\index.js
import React from './react';
import ReactDOM from './react-dom';
class Counter extends React.Component { //

他会比较两个状态相等就不会刷新视图 PureComponent是浅比较

  static defaultProps = {
    name: '

珠峰架构

'
  };
  constructor(props) {
    super(props);
    this.state = { number: 0 }
    console.log('Counter 1.constructor')
  }
  componentWillMount() { //

取本地的数据 同步的方式:采用渲染之前获取数据,只渲染一次

    console.log('Counter 2.componentWillMount');
  }
  componentDidMount() {
    console.log('Counter 4.componentDidMount');
  }
  handleClick = () => {
    this.setState({ number: this.state.number + 1 });
  };
  // react

可以shouldComponentUpdate方法中优化 PureComponent 可以帮我们做这件事

  shouldComponentUpdate(nextProps, nextState) { //

代表的是下一次的属性 和 下一次的状态

    console.log('Counter 5.shouldComponentUpdate');
    return nextState.number % 2 === 0;
    // return nextState.number!==this.state.number; //

如果此函数种返回了false 就不会调用render方法了

  } //

不要随便用setState 可能会死循环

  componentWillUpdate() {
    console.log('Counter 6.componentWillUpdate');
  }
  componentDidUpdate() {
    console.log('Counter 7.componentDidUpdate');
  }
  render() {
    console.log('Counter 3.render');
    return (
      <div>
        <p>{this.state.number}</p>
        {this.state.number === 4 ? null : <ChildCounter count={this.state.number} />}
        <button onClick={this.handleClick}>+</button>
      </div>
    )
  }
}
class ChildCounter extends React.Component {
  componentWillUnmount() {
    console.log(' ChildCounter 6.componentWillUnmount')
  }
  componentWillMount() {
    console.log('ChildCounter 1.componentWillMount')
  }
  render() {
    console.log('ChildCounter 2.render')
    return (<div>
      {this.props.count}
    </div>)
  }
  componentDidMount() {
    console.log('ChildCounter 3.componentDidMount')
  }
  componentWillReceiveProps(newProps) { //

第一次不会执行,之后属性更新时才会执行

    console.log('ChildCounter 4.componentWillReceiveProps')
  }
  shouldComponentUpdate(nextProps, nextState) {
    console.log('ChildCounter 5.shouldComponentUpdate')
    return nextProps.n % 3 === 0; //

子组件判断接收的属性 是否满足更新条件 为true则更新

  }
}
ReactDOM.render(<Counter />, document.getElementById('root'));
/**
click 1
Counter 1.constructor
Counter 2.componentWillMount
Counter 3.render
ChildCounter 1.componentWillMount
ChildCounter 2.render
ChildCounter 3.componentDidMount
Counter 4.componentDidMount
click 2
Counter 5.shouldComponentUpdate
click 3
Counter 5.shouldComponentUpdate
Counter 6.componentWillUpdate
Counter 3.render
ChildCounter 4.componentWillReceiveProps
Counter 5.shouldComponentUpdate
Counter 7.componentDidUpdate
click3
Counter 5.shouldComponentUpdate
click4
Counter 5.shouldComponentUpdate
Counter 6.componentWillUpdate
Counter 3.render
ChildCounter 6.componentWillUnmount
Counter 7.componentDidUpdate
click5
Counter 5.shouldComponentUpdate
click6
Counter 5.shouldComponentUpdate
Counter 6.componentWillUpdate
Counter 3.render
ChildCounter 1.componentWillMount
ChildCounter 2.render
ChildCounter 3.componentDidMount
Counter 7.componentDidUpdate
click7
Counter 5.shouldComponentUpdate
click8
Counter 5.shouldComponentUpdate
Counter 6.componentWillUpdate
Counter 3.render
ChildCounter 4.componentWillReceiveProps
Counter 5.shouldComponentUpdate
Counter 7.componentDidUpdate
 */
9.2 src\react-dom.js
src\react-dom.js
+import { REACT_TEXT, REACT_FORWARD_REF_TYPE } from "./constants";+import { addEvent } from "./event";
function render(vdom, container) {  mount(vdom, container);}export function mount(vdom, container) {  let newDOM = createDOM(vdom);  container.appendChild(newDOM);  if (newDOM.componentDidMount) newDOM.componentDidMount();}export function createDOM(vdom) { let { type, props, ref } = vdom;  let dom;  if (type && type.$$typeof === REACT_FORWARD_REF_TYPE) {    return mountForwardComponent(vdom);  } else if (type === REACT_TEXT) {    dom = document.createTextNode(props.content);  } else if (typeof type === "function") {    if (type.isReactComponent) {      return mountClassComponent(vdom);    } else {      return mountFunctionComponent(vdom);    }  } else {    dom = document.createElement(type);  }  if (props) {    updateProps(dom, {}, props);    if (typeof props.children == "object" && props.children.type) {      mount(props.children, dom);    } else if (Array.isArray(props.children)) {      reconcileChildren(props.children, dom);    }  }  vdom.dom = dom;  if (ref) ref.current = dom;  return dom;}function mountForwardComponent(vdom) {  let { type, props, ref } = vdom;  let renderVdom = type.render(props, ref);  vdom.oldRenderVdom = renderVdom;  return createDOM(renderVdom);}function mountClassComponent(vdom) {  let { type, props, ref } = vdom;  let classInstance = new type(props);+ vdom.classInstance = classInstance;  if (ref) ref.current = classInstance;  if (classInstance.componentWillMount) classInstance.componentWillMount();  let renderVdom = classInstance.render();+ classInstance.oldRenderVdom = vdom.oldRenderVdom = renderVdom;  let dom = createDOM(renderVdom);  if (classInstance.componentDidMount)    dom.componentDidMount = classInstance.componentDidMount.bind(classInstance);  return dom;}function mountFunctionComponent(vdom) {  let { type, props } = vdom;  let renderVdom = type(props);  vdom.oldRenderVdom = renderVdom;  return createDOM(renderVdom);}function updateProps(dom, oldProps, newProps) {  for (let key in newProps) {    if (key === "children") {      continue;    }    if (key === "style") {      let style = newProps[key];      for (let attr in style) {        dom.style[attr] = style[attr];      }    } else if (key.startsWith("on")) {      addEvent(dom, key.toLocaleLowerCase(), newProps[key]);    } else {      dom[key] = newProps[key];    }  }}export function findDOM(vdom) {  let { type } = vdom;  let dom;  if (typeof type === "function") {    dom = findDOM(vdom.oldRenderVdom);  } else {    dom = vdom.dom;  }  return dom;}+function unMount(vdom) {+  let currentDOM = findDOM(vdom);+  if (vdom.classInstance && vdom.classInstance.componentWillUnmount) {+    vdom.classInstance.componentWillUnmount();+  }+  if (vdom.props && vdom.props.ref) {+    vdom.props.ref.current = null;+  }+  Object.keys(vdom.props).forEach((propName) => {+    if (propName.slice(0, 2) === "on") {+      const eventName = propName.toLowerCase().slice(0, 2);+      currentDOM.removeEventListener(eventName, vdom.props[propName]);+    }+  });+  if (vdom.props.children) {+    let children = Array.isArray(vdom.props.children) ? vdom.props.children : [vdom.props.children];+    children.forEach(unMount);+  }+  currentDOM.parentNode.removeChild(currentDOM);+}+export function compareTwoVdom(parentDOM, oldVdom, newVdom,nextDOM) {+  if (!oldVdom && !newVdom) {+    //

老和新都是没有

+    return;+  } else if (!!oldVdom && !newVdom) {+    //

老有新没有

+    unMount(oldVdom);+  } else if (!oldVdom && !!newVdom) {+    //

老没有新的有

+    let newDOM = createDOM(newVdom);+    if (nextDOM) parentDOM.insertBefore(newDOM, nextDOM);+    else parentDOM.appendChild(newDOM);+    if (newDOM.componentDidMount) newDOM.componentDidMount();+    return;+  } else if (!!oldVdom && !!newVdom && oldVdom.type !== newVdom.type) {+    //

新老都有,但类型不同

+    let newDOM = createDOM(newVdom);+    unMount(oldVdom);+    if (newDOM.componentDidMount) newDOM.componentDidMount();+  } else {+    updateElement(oldVdom, newVdom);+  }+}+function updateElement(oldVdom, newVdom) {+    if (oldVdom.type === REACT_TEXT && newVdom.type === REACT_TEXT) {+       let currentDOM = newVdom.dom = findDOM(oldVdom);+       if (oldVdom.props.content !== newVdom.props.content) {+           currentDOM.textContent = newVdom.props.content;+       }+       return;+    }else if (typeof oldVdom.type === 'string') {+        let currentDOM = newVdom.dom = findDOM(oldVdom);+        updateProps(currentDOM, oldVdom.props, newVdom.props);+        updateChildren(currentDOM, oldVdom.props.children, newVdom.props.children);+    } else if (typeof oldVdom.type === 'function') {+        if (oldVdom.type.isReactComponent) {+            newVdom.classInstance = oldVdom.classInstance;+            updateClassInstance(oldVdom, newVdom);+        } else {+            updateFunctionComponent(oldVdom, newVdom);+        }+    }+}+function updateFunctionComponent(oldVdom, newVdom) {+    let parentDOM = findDOM(oldVdom).parentNode;+    let { type, props } = newVdom;+    let newRenderVdom = type(props);+    compareTwoVdom(parentDOM, oldVdom.oldRenderVdom, newRenderVdom);+    newVdom.oldRenderVdom = newRenderVdom;+}+function updateClassInstance(oldVdom, newVdom) {+    let classInstance = newVdom.classInstance = oldVdom.classInstance;+    newVdom.oldRenderVdom = oldVdom.oldRenderVdom;+    if (classInstance.componentWillReceiveProps) {+        classInstance.componentWillReceiveProps();+    }+    classInstance.updater.emitUpdate(newVdom.props);+}+function updateChildren(parentDOM, oldVChildren, newVChildren) {+    oldVChildren = Array.isArray(oldVChildren) ? oldVChildren : oldVChildren ? [oldVChildren] : [];+    newVChildren = Array.isArray(newVChildren) ? newVChildren : newVChildren ? [newVChildren] : [];+    let maxLength = Math.max(oldVChildren.length, newVChildren.length);+    for (let i = 0; i < maxLength; i++) {+       let nextVNode = oldVChildren.find((item,index)=>index>i&&item&&findDOM(item));+       compareTwoVdom(parentDOM, oldVChildren[i], newVChildren[i],nextVNode&&findDOM(nextVNode));+    }+}function reconcileChildren(childrenVdom, parentDOM) {  for (let i = 0; i < childrenVdom.length; i++) {    let childVdom = childrenVdom[i];    mount(childVdom, parentDOM);  }}const ReactDOM = {  render,};export default ReactDOM;

本站总访问 — 次