在实现自己的react之简单rendering中我们实现了简单的render方法。在这节中将会为我们的Feact添加componentWillMount和componentDidMount方法。
完善createClass
在上一节中的createClass方法中只支持render方法,如下:
const Feact = {
createClass(spec) {
function Constructor(props) {
this.props = props;
}
// 我们只是将spec的render方法赋值,忽略了其他的方法
Constructor.prototype.render = spec.render;
return Constructor;
}
...
}
对该方法进行简单的修改,即将spec全部添加到Constructor的原型对象中。这样我们就可以获取到用户定义的所有方法了。
const Feact = {
createClass(spec) {
function Constructor(props) {
this.props = props;
}
Constructor.prototype =
Object.assign(Constructor.prototype, spec);
return Constructor;
}
...
}
完善mountComponent
在第一节中为了能够支持自定义组件返回组件,我们在FeactCompositeComponentWrapper#mountComponent中使用了while循环,这种方式使得生命周期的方法(比如componentWillMount)调用变得非常苦难。
第一节中的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会循环调用render方法,直到遇到原生DOM元素。这种方式的问题是子组件在整个生命周期中是不可见的,也就是说只有子组件的render方法被调用了。
将mountComponent方法进行修改为:
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);
}
}
这次修改看起来添加了很多的代码,实际上我们只是将mounting的代码移到了FeactReconciler中。在后续的工作中FeactReconciler会有更多的功能。
在Feact.render方法中也有mountComponent的代码,我们也使用FeactReconciler进行替换:
const Feact = {
...
render(element, container) {
const wrapperElement =
this.createElement(TopLevelWrapper, element);
const componentInstance =
new FeactCompositeComponentWrapper(wrapperElement);
return FeactReconciler.mountComponent(
componentInstance,
container
);
}
}
添加componentWillMount和componentDidMount
在做完了上面的工作后,为组件添加componentWillMount和componentDidMount生命周期的方法就非常简单了。只需要在performInitialMount方法前后添加我们的方法调用即可。
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;
},
...
}