zoukankan      html  css  js  c++  java
  • 实现一个react系列三:生命周期

    前言

    本文主要参考了从零开始实现一个React从 0 到 1 实现React
    上一篇实现一个react系列二:渲染组件中说了组件是如何渲染的,本本来介绍下react中的生命周期。
    注意,本文主要理解是去react中的生命周期,并没有去实现react中最新的生命周期。

    生命周期

    react中生命周期是组件在不同时期运行的函数。如下图所示:(图片来源

    主要三个阶段:挂载阶段、更新阶段和卸载阶段。

    实现

    先将函数定义的组件和类定义的组件都转为类定义的组件,方便统一处理。

      if (typeof vdom.tag === 'function') {
        // 将组件都转为类定义的组件,
        const component = createComponent(vdom, vdom.attrs)
        // 更新组件 props
        setComponentProps(component, vdom.attrs)
        return component.base
      }
      
    
    • createComponent
      const createComponent = (vdom, props) => {
        let component
        // 类定义的组件,直接返回实例
        if (vdom.tag.prototype && vdom.tag.prototype.render) {
          component = new vdom.tag(props)
        } else {
          // 函数定义的组件,添加 render 方法,为了获取函数中 jsx 转化的虚拟 dom
          component = new vdom.tag(props)
          component.render = function () {
            return vdom.tag(props)
          }
        }
        return component
      }
    
    • setComponentProps:更新 props
      该方法用来加载及更新props,此时,组件还没有render,所以可以在该方法中加载 componentWillMountcomponentWillReceiveProps 钩子。
      const setComponentProps = (component, props) => {
        // 第一次渲染时,挂载 componentWillMount 钩子
        if (!component.base && component.componentWillMount) {
          component.componentWillMount()
        } else if (component.base && component.componentWillReceiveProps) {
          // 更新阶段,props 改变时,挂载 componentWillReceiveProps 钩子
          component.componentWillReceiveProps(props)
        }
        component.props = props
        // 渲染组件
        renderComponent(component)
      }
    
    • renderComponent:渲染组件
      渲染组件,setState时直接调用该方法。
      const renderComponent = (component) => {
        // 更新阶段,挂载 shouldComponentUpdate 钩子
        if (component.base && component.shouldComponentUpdate) {
          const bool = component.shouldComponentUpdate(component.props, component.state)
          if (!bool && bool !== undefined) {
            return false
          }
        }
        // 更新阶段,挂载 componentWillUpdate 钩子
        if (component.base && component.componentWillUpdate) {
          component.componentWillUpdate()
        }
        // 获得虚拟dom
        const rendered = component.render()
        // 设置是否是更新阶段的标识符,同时也是一个真实的dom节点
        const base = _render(rendered)
        // 更新阶段,挂载 componentDidUpdate 钩子
        if (component.base && component.componentDidUpdate) {
          component.componentDidUpdate()
        } else if (component && component.componentDidMount) {
          // 挂载阶段,挂载 componentDidMount 钩子
          component.componentDidMount()
        }
        if (component.base && component.base.parentNode) {
          // setState 时,新的 dom 替换掉之前的 dom
          component.base.parentNode.replaceChild(base, component.base)
        }
        component.base = base
      }
    

    下面我们来实验下效果如何。

    import React from "./react"
    import ReactDom from "./reactDom"
    
    class World extends React.Component {
      render() {
        return <div>{this.props.count}</div>
      }
    }
    class Hello extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          count: 0
        }
      }
      componentWillMount() {
        console.log("componentWillMount")
      }
      componentDidMount() {
        console.log("componentDidMount")
      }
      shouldComponentUpdate(nextProps, nextState) {
        console.log("shouldComponentUpdate", nextProps, nextState)
      }
      componentWillUpdate() {
        console.log("componentWillUpdate")
      }
      componentDidUpdate() {
        console.log("componentDidUpdate")
      }
      addCount() {
        const { count } = this.state
        this.setState({
          count: count + 1
        })
      }
      render() {
        console.log("render")
        return (
          <div ha="lou">
            <World count={this.state.count} />
            <button onClick={this.addCount.bind(this)}> + </button>
          </div>
        )
      }
    }
    
    ReactDom.render(<Hello />, document.getElementById("root"))
    
    

    结果如下,大致样子是有了。

    小结

    react的生命周期分为三个阶段,挂载阶段、更新阶段和卸载阶段。在实现时,我们先将函数定义的组件和类定义的组件都转成类定义的组件,(主要是将函数定义的组件,添加一个render方法,获取到虚拟dom),然后我们设置一个标识符来标识组件在什么阶段,以此来实现不同的生命周期方法。
    附上本文代码

  • 相关阅读:
    vue-路由传参
    ES6模板字符串
    es6中Set和Map数据结构
    本周面试题
    var、let和const定义变量的特点
    修改this的指向
    Echarts图表插件
    ES6学习
    swiper插件学习
    每日刷题4
  • 原文地址:https://www.cnblogs.com/yangrenmu/p/10960720.html
Copyright © 2011-2022 走看看