In part one we established basic rendering in Feact. That touched upon the most important lifecycle method, render, and now we are going to add in componentWillMount and componentDidMount support to Feact.
The series
- part one: basic rendering
- part two: componentWillMount and componentDidMount <- you are here
- part three: basic updating
- part four: setState
- part five: transactions
disclaimer
First, fix createClass
createClass back in part one only supported render
const       createClass(spec)               function                       this.props props ;               }
               // we pluck render off and ignore the rest of spec                         Constructor.prototype.render spec .render;
               return       }       ...}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.
const       createClass(spec)               function                       this.props props ;               }
               Constructor.prototype                       Object.assign(Constructor.prototype, spec );
               return       }       ...}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.
Here's mountComponent as it stood in part one
class       constructor(element)               this._currentElement element ;       }
       mountComponent(container)               const               const componentInstance  =               let element  = componentInstance .render();
               while element .type            element             =               }
               const domComponentInstance  =               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.
To fix this, let's have something else do the mounting for us
class       ...       mountComponent(container)               const               const componentInstance  =                       new               this._instance componentInstance ;
               const markup  =               return markup ;       }
       performInitialMount(container)               const renderedElement  =               const child  =               this._renderedComponent child ;
               return container );       }}
const       mountComponent(internalInstance, container )               return internalInstance .mountComponent(container);       }};
function       if element .type               return       } element .type               return       }}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.
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
const       ...       render(element, container )               const wrapperElement  =                       this.createElement(TopLevelWrapper, element );
               const componentInstance  =                       new               return            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.
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
class       ...       mountComponent(container)               const               const componentInstance  =                       new               this._instance componentInstance ;
               if            componentInstance            .componentWillMount();               }
               const markUp  =               if            componentInstance            .componentDidMount();               }
               return markUp ;       },       ...}Concluding part two
That wraps up part two. Here is a fiddle encompassing all we've done
JS FiddleIn part three, we'll add support for updates.