欢迎来真孝善网,为您提供真孝善正能量书籍故事!

深入解析React组件的首次实例化和渲染过程

时间:11-15 神话故事 提交错误

各位老铁们好,相信很多人对深入解析React组件的首次实例化和渲染过程都不是特别的了解,因此呢,今天就来为大家分享下关于深入解析React组件的首次实例化和渲染过程以及的问题知识,还望可以帮助大家,解决大家的一些困惑,下面一起来看看吧!

基于我的理解,跟React源码以及外国小哥的实现,有了这篇文章。

1、createElement、createClass实现

我们已经编写了组件类

类HelloWorld 扩展组件{

静态默认属性={

props: "道具"

}

构造函数(道具){

超级(道具);

这个.状态={

state: "状态"

}

}

组件WillMount() {

console.log("componentWillMount")

}

组件DidMount() {

console.log("componentDidMount")

}

使成为() {

返回(

Hello World

);

}

} 执行渲染函数就会在页面中渲染

ReactDOM.render(,

document.getElementById("root")

);之所以能够做到这一点,实际上是因为JSX。如果你对JSX 不太清楚,可以看看这里的JSX 介绍。

当然这里我们不会实现JSX 语法解析器,这不是本文的重点。分析完之后我们来分析一下。

ReactDOM.render(

React.createElement(HelloWorld),

document.getElementById("root")

);HelloWorld是我们编写的一个类。我们习惯用es6来写。上面我们经常写的class HelloWorld extends Component {}实际上会调用createClass,如下:

const HelloWorld=React.createClass({

获取默认属性() {

console.log("getDefaultProps")

返回{

props: "道具"

}

},

获取初始状态() {

console.log("getInitialState")

这个.状态={

state: "状态"

}

},

组件WillMount() {

console.log("componentWillMount");

},

组件DidMount() {

console.log("componentDidMount");

},

使成为() {

return React.createElement("h1", null, "Hello World");

}

});所以我们首先实现React.createClass和React.createElement:

常量反应={

createElement(类型、道具、子元素) {

常量元素={

类型,

props: 道具|| {}

};

如果(孩子){

element.props.children=孩子;

}

返回元素;

},

创建类(规范){

函数构造函数(道具){

this.props=道具;

if (this.getInitialState) {

this.getInitialState()

}

}

//构造函数的原型对象添加了我们createClass时定义的方法

Constructor.prototype=Object.assign(Constructor.prototype, spec);

如果(spec.getDefaultProps) {

Constructor.defaultProps=spec.getDefaultProps();

}

//返回构造函数

返回构造函数;

},

};接下来我们要看看ReactDom.render函数。这个函数做了3 件事

为顶层ReactElement包裹一层Wrapper(原因请看下文)并实例化生成ReactCompositeComponentWrapper进行渲染(这里比较复杂,下面分析)

ReactDom.render:

const ReactDom={

渲染(元素,容器){

//终于明白为什么这里元素需要再包裹一层了。

//在ReactCompositeComponentWrapper的performInitialMount方法中,

//我们通过组件的render()获取renderedElement。

//顶层ReactElement不是通过render()获得的,所以我们只能用一层TopLevelWrapper包裹它

constwrapperElement=React.createElement(TopLevelWrapper, 元素);

const componentInstance=new ReactCompositeComponentWrapper(wrapperElement);

return ReactReconciler.mountComponent(componentInstance, 容器);

}

}

TopLevelWrapper的实现:

const TopLevelWrapper=函数(props) {

this.props=道具;

};

TopLevelWrapper.prototype.render=function() {

返回this.props;

};

ReactReconciler:

const ReactReconciler={

mountComponent(内部实例,容器){

返回内部实例.mountComponent(容器);

}

};上面的流程基本上是这样的:

编写我们的组件HelloWorld,它定义了生命周期函数和自定义函数。这时候会调用React.createClass调用React.createClass,所以会先执行getDefaultProps(生命周期getDefaultProps在这一步执行),MyComponent会作为React.createElement使用。传入类型参数,创建一个ReactElement,传入创建的ReactElement和容器参数,在ReactDom.render方法中调用ReactDom.render,先用一层TopLevelWrapper包裹顶层ReactElement(原因在源码中分析)代码),然后生成ReactCompositeComponentWrapper

ReactCompositeComponentWrapper:

class ReactCompositeComponentWrapper {

构造函数(元素){

this._element=元素;

}

安装组件(容器){

//第一次this._element.type==TopLevelWrapper

//第二次this._element.type==createClass 的构造函数

const Component=this._element.type;

const componentInstance=new Component(this._element.props);

this._instance=组件实例;

if (componentInstance.componentWillMount) {

组件实例.componentWillMount();

}

const 标记=this.performInitialMount(container);

if (componentInstance.componentDidMount) {

componentInstance.componentDidMount();

}

返回标记;

}

执行初始安装(容器){

//render() 返回props 对象。我们知道ReactElement曾经被wrapperElement包装为props。

const renderElement=this._instance.render();

//根据不同类型的ReactElement实例化

const child=instantiateReactComponent(renderedElement);

控制台.log(子)

this._renderedComponent=子级;

//这实际上是一个递归调用,实例化父组件,然后实例化子组件。

返回ReactReconciler.mountComponent(child, 容器);

}

生成ReactCompositeComponentWrapper后,调用ReactmountComponent方法。第一次进入时,由于Reactelement.type为TopLevelWrapper,因此会生成一个TopLevelWrapper的实例。

生成了一个TopLevelWrapper的实例,但是这个实例的构造函数没有componentWillMount方法。输入performInitialMount方法。

在performInitialMount方法中,我们通过TopLevelWrapper定义的render方法获取我们的顶级ReactElement

获取到这个ReactElement后,将其传递给instantiateReactComponent并返回一个ReactCompositeComponentWrapper。 ReactCompositeComponentWrapper._element的类型是createCalss的Constructor。

instantiateReactComponent:

函数instantiateReactComponent(元素){

if (typeof element.type==="字符串") {

返回新的ReactDOMComponent(元素);

} else if (typeof element.type==="函数") {

返回新的ReactCompositeComponentWrapper(element);

}

}

ReactDOMComponent

/**

* ReactDOM组件类

* 用于渲染成真实的dom

*/

类ReactDOMComponent {

构造函数(元素){

this._element=元素;

}

安装组件(容器){

const domElement=document.createElement(this._element.type);

const textNode=document.createTextNode(this._element.props.children);

domElement.appendChild(textNode);

容器.appendChild(domElement);

this._hostNode=domElement;

返回dom元素;

}

}最后总结一下整体流程:(建议边看流程和源码边思考)

编写我们的组件HelloWorld,它定义了生命周期函数和自定义函数。这时候会调用React.createClass

React.createClass被调用,所以会先执行getDefaultProps(生命周期的getDefaultProps就是在这一步执行的)

将MyComponent 作为React.createElement 的类型参数传递以创建ReactElement

传入创建的ReactElement和容器参数,调用ReactDom.render

在ReactDom.render方法中,首先会用一层TopLevelWrapper包裹最顶层的ReactElement(原因在源码中分析),然后会生成ReactCompositeComponentWrapper

然后调用ReactCompositeComponentWrapper的mountComponent方法。第一次输入的时候,因为Reactelement.type是TopLevelWrapper,所以会生成一个TopLevelWrapper的实例。

生成了一个TopLevelWrapper的实例,但是这个实例的构造函数没有componentWillMount方法。输入performInitialMount方法。

在performInitialMount方法中,我们通过TopLevelWrapper定义的render方法获取我们的顶级ReactElement

获取到这个ReactElement后,将其传递给instantiateReactComponent并返回一个ReactCompositeComponentWrapper。 ReactCompositeComponentWrapper._element的类型是createCalss的Constructor。

此时递归回到ReactCompositeComponentWrapper的mountComponent方法。此时this._element.type就成为了createClass的Constructor。 getInitialState 在构造函数实例化时执行。这个Constructor的原型对象添加了我们写的类的方法(生命周期getInitialState就是在这一步执行的)

此时我们生成的实例已经可以访问componentWillMount方法了,因此执行了componentWillMount方法(在生命周期的这一步中执行了componentWillMount)

然后进入performInitialMount方法,通过ReactCompositeComponentWrapper的render方法获取底层的ReactElement,也就是我们写的类MyComponent的render方法(这一步执行了生命周期函数render)

此时输入instantiateReactComponent将会返回一个ReactDOMComponent实例。我们知道ReactDOMComponent负责真正的渲染,所以页面上渲染的是Hello World。

然后返回ReactCompositeComponentWrapper的mountComponent,继续执行componentDidMount(生命周期的componentDidMount就是在这一步执行的)

用户评论

念初

这篇文章正好是我现在需要的!一直想学习 React 模仿组件渲染的过程。

    有12位网友表示赞同!

颓废i

很期待看到文章里对 React 初始实例化的分析,希望能理解它的原理。

    有15位网友表示赞同!

爱你心口难开

模拟实现总是能更直观地理解技术的内层机制,这篇博客很有价值!

    有7位网友表示赞同!

陌然淺笑

我最近在研究前端框架,学习 React 是必不可少的,这个帖子特别适合我。

    有15位网友表示赞同!

敬情

React 这种组件化的方式真的很棒,希望能通过文章更加深入的了解。

    有16位网友表示赞同!

抓不住i

详细分析是重点,这样才能真正的弄懂 React 组件的渲染流程。

    有11位网友表示赞同!

孤廖

希望文章能涵盖实例化阶段的关键步骤,以及常见错误和解决方案。

    有7位网友表示赞同!

妄灸

模拟实现的过程应该能够让我们更容易理解各种状态的变化和影响.

    有6位网友表示赞同!

罪歌

React 的渲染机制真的很有趣,期待这篇文章带给我新的见解。

    有6位网友表示赞同!

赋流云

文章里提到的详细分析,会不会包含代码示例呢?

    有5位网友表示赞同!

风中摇曳着长发

学习 React 的过程中,模拟实现是一个很好的学习方法,尤其适合初学者。

    有20位网友表示赞同!

玩味

终于有人写了关于 React 初始实例化的详细指南了!太棒了!

    有8位网友表示赞同!

放血

期待通过文章学习到如何用代码去模拟 React 组件的状态变化和渲染过程。

    有9位网友表示赞同!

尘埃落定

这篇 Blog 文章的主题很有吸引力,希望能够解答我一些困惑的地方。

    有16位网友表示赞同!

稳妥

我一直想理解 React 的实际工作原理,这篇文章应该能帮我解决这个问题。

    有12位网友表示赞同!

你与清晨阳光

文章里应该包含一些关于 React 生态系统及其工具的信息,会更加完善!

    有16位网友表示赞同!

苏樱凉

通过模拟实现学习,能够更好地掌握 React 组件架构和组件之间的交互方式。

    有5位网友表示赞同!

作业是老师的私生子

希望文章的内容清晰易懂,适合各种经验水平的读者。

    有14位网友表示赞同!

【深入解析React组件的首次实例化和渲染过程】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活