preact 源码学习系列之二:组件的渲染与更新

Posted 前端控

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了preact 源码学习系列之二:组件的渲染与更新相关的知识,希望对你有一定的参考价值。

在中,我们已经掌握了“如何解析渲染一段 JSX 结构”。今天,我们进一步研究:如何解析、渲染和更新组件。

变量的解析

在研究组件解析之前,我们先来看个更简单的例子。

 
   
   
 
  1. import {h, render, Component} from '../../preact';

  2. class Person extends Component {

  3.    constructor() {

  4.        super();

  5.        this.state = {

  6.            name: "youngwind"

  7.        }

  8.    }

  9.    render() {

  10.        return (

  11.            <div>

  12.                {this.state.name}

  13.            </div>

  14.        )

  15.    }

  16. }

  17. render(<Person />, document.body);

问题:在渲染 Person 组件的时候,如何将 this.state.name 解析成真实值 "youngwind" 呢?是用正则匹配替换吗? 

答案:不需要处理,因为 babel 已经帮我们处理好了。 请看编译后的代码。

由图中我们可以看出:由于 this.state.name被当做函数参数传递给 h 函数,因此 h 函数在执行的时候会对其进行自动求值。也就是说,对于变量的解析,我们并不需要做任何特殊处理。

组件标签的解析

再看一个更复杂的例子。

 
   
   
 
  1. import {h, render, Component} from '../../preact';

  2. class Person extends Component {

  3.    constructor() {

  4.        super();

  5.        this.state = {

  6.            name: "youngwind",

  7.            age: 25

  8.        }

  9.    }

  10.    render() {

  11.        return (

  12.            <div>

  13.                <Name name={this.state.name}/>

  14.                <Age age={this.state.age}/>

  15.            </div>

  16.        )

  17.    }

  18. }

  19. class Name extends Component {

  20.    render(props) {

  21.        return (

  22.            <div>

  23.                {props.name}

  24.            </div>

  25.        )

  26.    }

  27. }

  28. class Age extends Component {

  29.    render(props) {

  30.        return (

  31.            <div>

  32.                {props.name}

  33.            </div>

  34.        )

  35.    }

  36. }

  37. render(<Person />, document.body);

编译后的代码如下:

preact 源码学习系列之二:组件的渲染与更新 由图中我们可以发现:babel 进行 JSX 解析时,对普通标签和组件标签的处理是类似的,只不过有两点不同。

  1. 对于组件来说,h 函数的第一个参数不是标签字符串,而是组件类;

  2. 所谓传递给组件的 props,其实就相当于给普通标签定义 attributes。

组件的渲染与更新

有了上面的基础,我们来看看如何实现组件的渲染和更新,举个例子。

 
   
   
 
  1. import {h, render, Component} from '../../preact';

  2. class Person extends Component {

  3.    constructor() {

  4.        super();

  5.        this.state = {

  6.            name: "youngwind",

  7.            age: 25

  8.        }

  9.    }

  10.    change() {

  11.        let {name, age} = this.state;

  12.        this.setState({

  13.            name: name + '啦',

  14.            age: age + 1

  15.        });

  16.    }

  17.    render() {

  18.        return (

  19.            <div>

  20.                <button onclick={this.change.bind(this)}>改变</button>

  21.                <Name name={this.state.name}/>

  22.                <Age age={this.state.age}/>

  23.            </div>

  24.        )

  25.    }

  26. }

  27. class Name extends Component {

  28.    render(props) {

  29.        return (

  30.            <div>

  31.                <label>姓名:</label>

  32.                <span>{props.name}</span>

  33.            </div>

  34.        )

  35.    }

  36. }

  37. class Age extends Component {

  38.    render(props) {

  39.        return (

  40.            <div>

  41.                <label>年龄:</label>

  42.                <span>{props.age}</span>

  43.            </div>

  44.        )

  45.    }

  46. }

  47. render(<Person />, document.body);

这段代码,我们期望的功能是:

  1. 通过 props 给 Name 和 Age 传递参数,初次渲染的时候分别显示 "youngwind" 和 "25";

  2. 点击“改变”按钮,调用 setState,触发 Name 和 Age 的重新渲染,显示 "youngwind啦" 和 "26"。

具体的实现逻辑较为繁复,难以用文字描述清楚,我画了个流程图,可以对比着我实现的代码看。 preact 源码学习系列之二:组件的渲染与更新

效果

最终实现的效果如下所示。(注意,效果图中控制台会输出一些生命周期的信息,这部分的代码我在 demo 中省略了,完整的代码请参考原文阅读。 )

后话

虽然在本文中已经实现了组件的更新,但是,并没有应用虚拟 DOM 的 diff 算法,之后有时间再去研究研究。


以上是关于preact 源码学习系列之二:组件的渲染与更新的主要内容,如果未能解决你的问题,请参考以下文章

PREACT学习笔记

PREACT学习笔记

原Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

从Preact中了解React组件和hooks基本原理

赠书Preact(React)核心原理详解

Preact 路由器:修改 URL