对React的粗浅认知(二)

        在之前的认知基础上,对react的功能进行多一步的了解。上一步是对react的JSX的渲染功能的实现,但这只是基础,但是react的意义在于他的组件化,接下来就是聊一下我对react组件化的认知

组件

        React定义组件的方式可以分为两种:函数和类,函数定义可以看做是类定义的一种简单形式。

createElement的变化

        在上一篇中,我们对React.createElement的实现 已经完成了:

function createElement( tag, attrs, ...children ) {
    return {
        tag,
        attrs,
        children
    }
}

           在前面我只是用来渲染原生的dom,对于组件来说createElement得到的参数是不同的:如果JSX片段的元素有组件在的话,那么createElement的第一个参数就是一个方法了,不会是字符串了。

        坦白来说,我有个组件<HelloWorld name="Hello" />,那么他的第一个参数就会是我定义的HelloWorld的方法了

function HelloWorld( props ) {
    return <h1>Hello, {props.name}</h1>;
}

其实这里只是告诉我们区别就是,如果有组件的在的话需要渲染,则tag会是一个函数而已

React.Component 组件类        

        上面说了通过函数的方法,这边讲一下类的方法:Reac.Component,这里看文档说是有一个继承React.Component

class HelloWorld extends React.Component {
    render() {
        return <h1>Hello, {this.props.name}</h1>;
    }
}

要搞懂如何继承, 首先先来实现这个类

Component

React.Component包含了一些预先定义好的变量和方法,我们来一步一步地实现它:
先定义一个Component类:

        class Component {}

state& props 

        通过继承React.Component定义的组件 他是会有自己的私有状态State(感觉这里跟vue的有点像了,本人是在从事vue开发工作),根据this.state获取到这个私有状态State之后,同时也能同通过this.props来传入数据 

class Component {
    constructor( props = {} ) {
        this.state = {};
        this.props = props;
    }
}

在这点看上去Vue其实跟React已经非常接近甚至相似了,

SetState

        组件内部的state的渲染结果相关,当state改变时通常会触发渲染,为了让React知道了改变了私有状态State,我们要通过setState方法去修改,这里我讲一句跟vue 的大差不差vue也是用这种方法进行的,不过他们更为明显的用了getter 和setter去修改和劫持相关的属性。

回到正题这里用Object.assign来做一个实现  在每次更新state后,我们会需要调用renderComponent来渲染组件的

import { renderComponent } from '../react-dom/render'
class Component {
    constructor( props = {} ) {
        // ...
    }

    setState( stateChange ) {
        // 将修改合并到state
        Object.assign( this.state, stateChange );
        renderComponent( this );
    }
}

render

        在上一篇已经实现了reander的封装与实现,他只实现了渲染原生的DOM,现在我们需要进行更改让他支持渲染组件。

在这前面加多一段话

unction render( vnode, container ) {
    return container.appendChild( _render( vnode ) );
}

function _render( vnode ) {

    if ( vnode === undefined || vnode === null || typeof vnode === 'boolean' ) vnode = '';

    if ( typeof vnode === 'number' ) vnode = String( vnode );

    if ( typeof vnode === 'string' ) {
        let textNode = document.createTextNode( vnode );
        return textNode;
    }
// 支持渲染组件 
 if ( typeof vnode.tag === 'function' ) {

        const component = createComponent( vnode.tag, vnode.attrs );

        setComponentProps( component, vnode.attrs );

        return component.base;
    }

    const dom = document.createElement( vnode.tag );

    if ( vnode.attrs ) {
        Object.keys( vnode.attrs ).forEach( key => {
            const value = vnode.attrs[ key ];
            setAttribute( dom, key, value );
        } );
    }

    vnode.children.forEach( child => render( child, dom ) );    // 递归渲染子节点

    return dom; 
}

组件渲染和生命周期

        上面的方法中用到了createComponentsetComponentProps两个方法,组件的生命周期方法也会在这里面实现。

        所谓生命周期方法大家都很熟了,也是一个关键点,他是一些在特殊时机执行的函数,例如componentDidMount方法会在组件挂载后执行

这里需要对createComponent来进行扩展修改了

// 创建组件
function createComponent( component, props ) {

    let inst;
    // 如果是类定义组件,则直接返回实例
    if ( component.prototype && component.prototype.render ) {
        inst = new component( props );
    // 如果是函数定义组件,则将其扩展为类定义组件
    } else {
        inst = new Component( props );
        inst.constructor = component;
        inst.render = function() {
            return this.constructor( props );
        }
    }

    return inst;
}

    setComponentProps方法用来更新props,在其中可以实现componentWillMountcomponentWillReceiveProps两个生命周期方法(这里不太理解了,我个人原以为是在生命周期执行中经历这些事,但是现在看来似乎并不是这样,而是在执行中,调用了生命周期函数

// set props
function setComponentProps( component, props ) {

    if ( !component.base ) {
        if ( component.componentWillMount ) component.componentWillMount();
    } else if ( component.componentWillReceiveProps ) {
        component.componentWillReceiveProps( props );
    }

    component.props = props;

    renderComponent( component );

}

renderComponent方法是用来渲染组件的,在上面的setState里会调用这个方法进行重新渲染,在这里可以实现几个生命周期的实现,componentWillUpdatecomponentDidUpdatecomponentDidMount这几个

export function renderComponent( component ) {

    let base;

    const renderer = component.render();

    if ( component.base && component.componentWillUpdate ) {
        component.componentWillUpdate();
    }

    base = _render( renderer );

    if ( component.base ) {
        if ( component.componentDidUpdate ) component.componentDidUpdate();
    } else if ( component.componentDidMount ) {
        component.componentDidMount();
    }

    if ( component.base && component.base.parentNode ) {
        component.base.parentNode.replaceChild( base, component.base );
    }

    component.base = base;
    base._component = component;

}

到此组件渲染已经完成了

                在此感觉是从API层面来实现了react的功能,但是目前的是重新渲染整个组件,这很明显非常的损耗功能,减少dom操作才是框架该做的,等待后续更新把~!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值