回顾一下 React 中组件

在 javascript 做 web 开发,少不了要提到组件,Vue 也好 React 也好在这当下流行框架都提出组件的概念,组件出现提升了代码的复用性

接下来以 React 为例,介绍一下组件概念在 React 不断版本迭代过程调整,从类到函数

组件

组件可能是函数还可能是类,在早期知道 React 组件是需要继承 React.Component 类的类,也就是类组件。这个类带有内部状态和生命周期,虽然很完备,但是对于许多场景也过于臃肿。

js 复制代码
import React, { Component } from 'react';

class MyComponent extends Component {
    constructor(props) {
        super(props);
        this.state = {
            // 初始状态
        };
    }

    render() {
        return (
            <div>
                {/* 组件渲染内容 */}
            </div>
        );
    }
}

export default MyComponent;

随着React 16.8的发布,引入了 Hooks,这使得原有函数组件(Functional Components)变得更加强大。现在,可以在不编写类的情况下使用状态和其他React特性。这种方法简化了组件的编写和理解,也是当前 React 开发的主流方式。

javascript 复制代码
function Box(){
    return (
        <div className='box' size="24">
            hello,<span>zidea</span>
        </div>
    )
}

定义一个函数,函数名为 Box ,这个函数返回一个 jsx 对象

javascript 复制代码
ReactDOM.render(<Box name={title}/>,document.querySelector("#root"));

传入一个名称为 title 作为 Box 的属性,这样就实现了一个简单函数组件。

接下来我们自己去实现将虚拟dom渲染到界面上过程,下面先实现一个 _render 方法接受vnode 对象作为参数。这里主要为熟悉如何将 component 渲染到界面上,并非去实现一个可用渲染函数,所以适当地简化过程,代码如下,主要将文本节点和对象节点来转换为 dom 对象

整理代码

javascript 复制代码
function _render(vnode){
    //TODO
    if(vnode === undefined ) return;
    // vnode is equal string
    if(typeof vnode === 'string'){
        //create textNode
        return document.createTextNode(vnode)
    }

    // deconstruct vnode
    const {tag,attrs} = vnode;

    //create dom object
    const dom = document.createElement(tag)

    if(attrs){
        // property key: className box
        Object.keys(attrs).forEach(key=>{
            const val = attrs[key]
            setAttribute(dom,key,val)
        })
    }

    vnode.children.forEach(child=>render(child,dom))

    return dom;
    
}

在 javascript 中,如果函数名称以下划线开头通常是私有方法。这里把渲染设置为私有方法,也就是渲染逻辑放置在 _render 方法中。然后 _render 方法主要就是讲虚拟节点处理 dom 节点返回出来。

  • return dom; 返回 dom 而不是将 dom 添加到容器节点中
  • return document.createTextNode(vnode) 通常
javascript 复制代码
function render(vnode,container){
    container.appendChild(_render(vnode))
}

渲染方法(_render)

javascript 复制代码
if(vnode === undefined || vnode === null || typeof vnode === 'boolean') vnode = '';

判断 tag 是函数,tag 可能是函数组件或类组件 if(typeof vnode.tag === 'function') 通过虚拟节点 tag 值来判断是否为组件,然后按组件进行处理

  1. 创建组件 const comp = createComponent(vnode.tag,vnode.attrs);
  2. 设置组件的属性 setComponentProps(comp,vnode.attrs);
  3. 组件渲染的节点返回对象 return comp.base; 这里我们不能返回组件,而需要将节点对象挂接到 comp 的 base 属性上,然后返回comp.base的个节点对象。

创建组件

javascript 复制代码
function createComponent(comp,props){
    //declare component instance
    let instance;
    // class component case
    if(comp.prototype && comp.prototype.render){
        instance = new comp(propos)
    }else{ // function component case 
        //conver function component to class component
        instance = new Component(props)
        //constructor prefer to function(component)

        instance.constructor = comp;
        //define render function
        instance.render = function(){
            //return jsx object
            return this.constructor(props)
        }
    }
    return instance;
}
  • 对于类组件,相对函数组件要好处理,只需要实例化(new)该类,然后将 props 做出参数传入即可。
  • 如果组件是函数组件,需要将函数组件转为类组件,这样做的好处是便于以后管理组件。这里在 react 文件夹下创建一个 component.js 类其中定义 Component 类
javascript 复制代码
class Component{
    constructor(props = {}){
        this.props = props;
        this.state = {};
    }
}

export default Component;
  • 在构造函数接收 props 参数,这是从外部传入的参数,然后内部维护组件的一个内部状态对象 state

  • 接下来问题是如何获取 jsx 对象,其实在函数组价,jsx 对象作为返回值,我们构造函数依然已经指向了该函数,只要 render 函数返回该函数的返回值即可。

javascript 复制代码
instance.render = function(){
    //return jsx object
    return this.constructor(props)
}

设置组件属性

javascript 复制代码
function setComponentProps(comp,props){
    //设置组件的属性
    comp.propos = props;
    renderComponent(comp)
}

渲染组件

javascript 复制代码
function renderComponent(comp){
    let base;
    //call render method to return jsx object
    const renderer = comp.render();
    //conver jsx to dom obj
    base = _render(renderer);
    
    console.log(base)

    comp.base = base
}
相关推荐
小白小白从不日白5 分钟前
react 组件通讯
前端·react.js
罗_三金16 分钟前
前端框架对比和选择?
javascript·前端框架·vue·react·angular
Fan_web1 小时前
JavaScript高级——闭包应用-自定义js模块
开发语言·前端·javascript·css·html
叫我:松哥1 小时前
基于Python flask的医院管理学院,医生能够增加/删除/修改/删除病人的数据信息,有可视化分析
javascript·后端·python·mysql·信息可视化·flask·bootstrap
好名字08212 小时前
monorepo基础搭建教程(从0到1 pnpm+monorepo+vue)
前端·javascript
c#上位机2 小时前
C#事件的用法
java·javascript·c#
万物得其道者成2 小时前
React Zustand状态管理库的使用
开发语言·javascript·ecmascript
小白小白从不日白2 小时前
react hooks--useReducer
前端·javascript·react.js
下雪天的夏风3 小时前
TS - tsconfig.json 和 tsconfig.node.json 的关系,如何在TS 中使用 JS 不报错
前端·javascript·typescript
diygwcom3 小时前
electron-updater实现electron全量版本更新
前端·javascript·electron