超级面板
文章目录
最新文章
最近更新
文章分类
标签列表
文章归档

React 内部原理,第二部分:添加 componentWillMount 和 componentDidMount

原文:React Internals, Part Two: componentWillMount and componentDidMount

In part one we established basic rendering in Feact. That touched upon the most important lifecycle method, render, and now we’re going to add in componentWillMount and componentDidMount support to Feact.

part one ,我们在 Feact 中建立了基本渲染。这涉及到最重要的生命周期方法,渲染(render),现在我们将在 Feact 添加 componentWillMountcomponentDidMount 的支持。

The series

全部译文:

首先,修复 createClass(First, fix createClass)

createClass back in part one only supported render

createClass 在第一部分中仅支持 render 方法:

const Feact = {
createClass(spec) {
function Constructor(props) {
this.props = props;
}

// we pluck render off and ignore the rest of spec
Constructor.prototype.render = spec.render;

return Constructor;
}
...
}

This is a simple fix, let’s add the entire spec to the component’s prototype. That allows methods like componentWillMount, but it also allows any arbitrary methods the user defined to be used.

这是一个简单的修复,我们将整个规范的接口添加到组件的原型。这将允许使用如 componentWillMount 的方法,但它也允许使用用户定义的任意方法。

const Feact = {
createClass(spec) {
function Constructor(props) {
this.props = props;
}

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

return Constructor;
}
...
}

解决 mountComponent 的快捷方式(Addressing mountComponent’s shortcut)

Back in part one, I noted that FeactCompositeComponentWrapper#mountComponent had taken a shortcut. This shortcut will prevent lifecycle methods such as componentWillMount from getting called.

回到第一部分,注意到 FeactCompositeComponentWrapper.mountComponent 采取了一个快捷实现。此快捷实现方式将阻止诸如 componentWillMount 之类的生命周期方法被调用。

Here’s mountComponent as it stood in part one

这是第一部分的 mountComponent

class FeactCompositeComponentWrapper {
constructor(element) {
this._currentElement = element;
}

mountComponent(container) {
const Component = this._currentElement.type;
const componentInstance = new Component(this._currentElement.props);

let element = componentInstance.render();

while (typeof element.type === 'function') {
element = (new element.type(element.props)).render();
}

const domComponentInstance = new FeactDOMComponent(element);
return domComponentInstance.mountComponent(container);
}
}

mountComponent is working its way down to a native element. As long as render() returns a composite component element, it calls render again until it finally gets a native element. The problem is these sub composite components are not privy to the entire lifecycle. In other words, their render method is being called, but that’s it. What we really need to do is properly mount all components.

mountComponent 正在不断向下调用直到返回一个原生元素。只要 render() 返回一个复合组件元素,它就一直调用 render ,直到它最终获得一个原生元素。问题是这些子复合组件不清楚整个生命周期。换句话说,它们的渲染方法被调用,就是这样。我们真正需要做的是正确挂载所有组件。

To fix this, let’s have something else do the mounting for us

为了解决这个问题,让我们为处理挂载

class FeactCompositeComponentWrapper {
...
mountComponent(container) {
const Component = this._currentElement.type;
const componentInstance = new Component(this._currentElement.props);
this._instance = componentInstance;

const markup = this.performInitialMount(container);

return markup;
}

performInitialMount(container) {
const renderedElement = this._instance.render();

const child = instantiateFeactComponent(renderedElement);
this._renderedComponent = child;

return FeactReconciler.mountComponent(child, container);
}
}

const FeactReconciler = {
mountComponent(internalInstance, container) {
return internalInstance.mountComponent(container);
}
};

function instantiateFeactComponent(element) {
if (typeof element.type === 'string') {
return new FeactDOMComponent(element);
} else if (typeof element.type === 'function') {
return new FeactCompositeComponentWrapper(element);
}
}

This is a fair amount of new code, but the basic idea is to move mounting out into another layer. That’s the job of FeactReconciler, which will also gain more jobs as we move forward. Over in React, there is ReactReconciler which is serving the same role.

这是相当数量的新代码,但基本思想是将挂载移至另一层。这是 FeactReconciler 的工作,随着我们的前进,也将有更多的工作要做。在 React 中,ReactReconciler 扮演同样的角色。

Remember the tight coupling that was called out in part one? It’s gone now, FeactCompositeComponentWrapper is usable in more places now, which is a good thing.

还记得在第一部分中提到的紧耦合?现在已经消失了,FeactCompositeComponentWrapper 现在可以在更多的地方使用,这是件好事。

调整 Feact.render()(Tweaking Feact.render()

Feact.render() is calling componentInstance.mountComponent(container) in part one. Let’s change that and instead have FeactReconciler deal with all mounting

Feact.render() 在第一部分中调用 componentInstance.mountComponent(container)。让我们改变一下,使用 FeactReconciler 处理所有的挂载。

const Feact = {
...
render(element, container) {
const wrapperElement = this.createElement(TopLevelWrapper, element);

const componentInstance = new FeactCompositeComponentWrapper(wrapperElement);

return FeactReconciler.mountComponent(
componentInstance,
container
);
}
}

And with that, all composite component elements will get properly mounted. This sets them up properly for participating in the entire Feact lifecycle.

现在,所有复合组件元素都将正确挂载。可以开始参与整个 Feact 生命周期。

最后添加 componentWillMount 和 componentDidMount(Finally adding componentWillMount and componentDidMount)

Now with all the setup out of the way, actually adding support for these two is simple. Just before mounting, call componentWillMount if it exists. Likewise, just after mounting, call componentDidMount if it exists

实际上,添加对这两个生命周期方法的支持很简单。在组件挂载之前,如果存在,调用 componentWillMount。同样的,在挂载之后,如果存在,调用 componentDidMount

class FeactCompositeComponentWrapper {
...
mountComponent(container) {
const Component = this._currentElement.type;
const componentInstance = new Component(this._currentElement.props);
this._instance = componentInstance;

if (componentInstance.componentWillMount) {
componentInstance.componentWillMount();
}

const markUp = this.performInitialMount(container);

if (componentInstance.componentDidMount) {
componentInstance.componentDidMount();
}

return markUp;
},
...
}

第二部分总结(Concluding part two)

That wraps up part two. Here is a fiddle encompassing all we’ve done

这就是第二部分,这是一个 fiddle 在线示例,包含我们目前所实现的代码:

fiddle 在线示例:fiddle

In part three, we’ll add support for updates.

第三部分 我们将添加组件更新的支持。