MyReact(二)——组件和状态

286 阅读1分钟
到目前为止MyReact还没解决的问题
  • 只有一个全局“组件”
  • 每次state改变,都要手动调用MyReact.render函数,触发完整虚拟dom的对比

组件基类-MyReact.Component解决上述两个问题

  • 通过组件基类可以创建组件实例
  • 组件实例内部维护自己的props和state,每次state改变会自动触发此组件对应的虚拟dom的对比,也就意味着状态不变其他组件不受影响

组件基类的构造函数为组件实例注入props和初始化state,它还应该有setState方法来改变state,并且自动触发对比函数。

//组件基类的定义
import { reconcile } from './render'
class Component{     
    constructor(props){        
    this.props = props        
    this.state = this.state || {}     
}     
setState(partitalState){        
    this.state = Object.assign({}, this.state, partitalState)        
    updateInstance(this.__internalInstance)             
} }
//由于组件状态改变触发的组件更新 
function updateInstance(internalInstance){    
    const element = internalInstance.element    
    const parentDom = internalInstance.dom.parentNode    
    reconcile(element, internalInstance, parentDom) 
} 
export default Component

有两种element

  • dom element:对应原生html元素,type的值是字符串,如"div",“TEXT ELEMENT”,对应dom实例
  • component element:对应自定义组件元素,如<MyComponent>,type的值是构造函数,对应组件实例

有三种和组件相关的实例:

  • 外层实例-wrapperInstance:构造函数返回的对象,保存了props,state和对组件实例的引用-__internalInstance
  • 内部实例-childInstance:挂在外层实例的render函数定义的实例对象,有且只有一个
  • 组件实例-instance:{ dom, element, childInstance, wrapperInstance }
function instantiate(element){    const { type, props} = element    if(typeof type == 'string'){        const isTextElement = type === TEXT_ELEMENT        //创建节点        const dom = isTextElement ? document.createTextNode(''): document.createElement(type)        //更新属性和事件        updateDomProperties(dom, [], props);        //添加子实例        const children = props.children         const childInstances = []        children.forEach(child => {                           const childInstance = instantiate(child)            dom.appendChild(childInstance.dom)            childInstances.push(childInstance)        })        //返回element对应的实例        return { element, dom, childInstances }    }else{        const instance = {}        const wrapperInstance = createWrapperInstance(element, instance)        const childElement = wrapperInstance.render()        const childInstance = instantiate(childElement)        const dom = childInstance.dom       // instance = { dom, element, childInstance, wrapperInstance }       Object.assign(instance, { dom, element, childInstance, wrapperInstance })       return instance    }}

完整代码 github.com/zhangwenhui…