ReactDOM.render(
<h1>Hello World</h1>,
document.getElementById('root')
);
// babel 转义以后,JSX语法实际上是React.createElement()的语法糖
ReactDOM.render(React.createElement(
'h1', // type--节点类型
null, // props
'Hello World' // children
), document.getElementById('root'));
// createElement 部分代码详细过程不作分析
export function createElement(type, config, children) {
...
// 返回一个ReactElement
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
}
// ReactElement 部分代码
const ReactElement = function(type, key, ref, self, source, owner, props) {
const element = {
// 标记惟一识别的元素类型
$$typeof: REACT_ELEMENT_TYPE,
// 元素的内置类型
type: type,
key: key,
ref: ref,
props: props,
// 记录建立此元素的组件
_owner: owner,
};
...
return element; // 最后返回一个element
}
复制代码
createElement对应的源码部分是ReactElement.js,感兴趣能够本身看看html
这里不细说JSX,感兴趣能够看看官网介绍JSXreact
版本16以前,不作分析,详细过程参考连接 ReactDom 组件渲染过程git
声明一个简单组件github
class Simple extends React.Component {
render() {
return (
<h1>Simple test</h1>
)
}
}
console.log(<Simple />); 复制代码
通过babel转义以后chrome
var Simple = (function(_React$Component2) {
// 继承 Component 的属性和方法
_inherits(Simple, _React$Component2);
function Simple() {
_classCallCheck(this, Simple);
return _possibleConstructorReturn(
this,
(Simple.__proto__ || Object.getPrototypeOf(Simple)).apply(this, arguments)
);
}
_createClass(Simple, [
{
key: "render",
value: function render() {
return _react2.default.createElement("h1", null, "Simple text");
}
}
]);
return Simple;
})(_react2.default.Component);
// 直接打印的是 createElement 返回的对象: 包括当前节点的全部信息。 即: `render` 方法
console.log(_react2.default.createElement(Simple, null));
// 实际返回 构造函数。
exports.default = Simple;
复制代码
打印结果数组
{$$typeof: Symbol(react.element), type: ƒ, key: null, ref: null, props: {…}, …}
$$typeof:Symbol(react.element)
key:null
props:{}
ref:null
type:ƒ Simple()
_owner:null
_store:{validated: false}
_self:null
_source:{fileName: "D:\CodeSpace\Scheele2\src\index.js", lineNumber: 33}
__proto__:Object
复制代码
先看chrome浏览器render过程,给你们一个印象,而后根据函数,逐一分析涉及DOM的部分 浏览器
源码位置babel
const ReactDOM: Object = {
...
render(
element: React$Element<any>,
container: DOMContainer,
callback: ?Function,
) {
return legacyRenderSubtreeIntoContainer(
null, // parent
element, // children
container, // Dom容器
false, // 渲染标记
callback, // 回调
);
},
}
复制代码
// 结合上方的render函数来看
function legacyRenderSubtreeIntoContainer( parentComponent: ?React$Component<any, any>, children: ReactNodeList, container: DOMContainer, forceHydrate: boolean, callback: ?Function, ) {
...
let root: Root = (container._reactRootContainer: any);
if (!root) {
// 初始化挂载,得到React根容器对象
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
container,
forceHydrate,
);
}
}
复制代码
function legacyCreateRootFromDOMContainer( container: DOMContainer, forceHydrate: boolean, // 渲染标记 ): Root {
const shouldHydrate =
forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
// 第一次渲染,删除其他的全部节点
if (!shouldHydrate) {
let warned = false;
let rootSibling;
while ((rootSibling = container.lastChild)) {
...
container.removeChild(rootSibling);
}
}
...
const isAsync = false; // 是否异步
// 返回一个根节点对象
return new ReactRoot(container, isAsync, shouldHydrate);
}
...
// 经过DOMRenderer建立一个root
function ReactRoot(container: Container, isAsync: boolean, hydrate: boolean) {
const root = DOMRenderer.createContainer(container, isAsync, hydrate);
this._internalRoot = root;
}
复制代码
源码位置app
// createContainer涉及到了React新推出的Fiber
export function createContainer( containerInfo: Container, isAsync: boolean, hydrate: boolean, ): OpaqueRoot {
return createFiberRoot(containerInfo, isAsync, hydrate);
}
复制代码
源码位置dom
// 最终返回的对象
export function createFiberRoot( containerInfo: any, isAsync: boolean, hydrate: boolean, ): FiberRoot {
...
// 没有改形成Fiber以前,节点类型可能就几种,Fiber以后嘛...
// 这里是将节点初始化成Fiber的节点,感兴趣能够看看Fiber,这里不细说
const uninitializedFiber = createHostRootFiber(isAsync);
let root;
// 这个是个 export const enableSchedulerTracing = __PROFILE__;
if (enableSchedulerTracing) {
...
}else {
// 最后返回的root对象
root = ({
current: uninitializedFiber,
containerInfo: containerInfo, // DOM容器
pendingChildren: null,
earliestPendingTime: NoWork,
latestPendingTime: NoWork,
earliestSuspendedTime: NoWork,
latestSuspendedTime: NoWork,
latestPingedTime: NoWork,
didError: false,
pendingCommitExpirationTime: NoWork,
finishedWork: null,
timeoutHandle: noTimeout,
context: null,
pendingContext: null,
hydrate,
nextExpirationTimeToWorkOn: NoWork,
expirationTime: NoWork,
firstBatch: null,
nextScheduledRoot: null,
}: BaseFiberRootProperties);
}
uninitializedFiber.stateNode = root;
return ((root: any): FiberRoot);
}
...
复制代码
初始化root对象完成以后,调用unbatchedUpdates函数
// 无论是if,仍是else,本质上都是初始化work = new ReactWork(),而后执行updateContainer操做
DOMRenderer.unbatchedUpdates(() => {
if (parentComponent != null) { // 若是根节点不为空,将节点渲染进去
root.legacy_renderSubtreeIntoContainer(
parentComponent,
children,
callback,
);
} else { // 渲染根节点
root.render(children, callback);
}
});
...
复制代码
ReactRoot.prototype.render = function( children: ReactNodeList, callback: ?() => mixed, ): Work {
const root = this._internalRoot;
const work = new ReactWork();
callback = callback === undefined ? null : callback;
...
if (callback !== null) {
work.then(callback);
}
// 执行updateContainer函数,返回一个work对象(参数就不解释了吧...)
DOMRenderer.updateContainer(children, root, null, work._onCommit);
return work;
};
复制代码
代码量过多,先贴出调用过程
// 这些函数调用的过程,能够简单理解成是为了配合Fiber的批度更新以及异步更新而进行的
updateContainerAtExpirationTime(element,container,parentComponent,expirationTime,callback)->
scheduleRootUpdate(current, element, expirationTime, callback) ->
scheduleWork(current, expirationTime) ->
requestWork(root, rootExpirationTime) ->
performWorkOnRoot(root, Sync, false) ->
renderRoot(root, false) ->
workLoop(isYieldy) -> // 开启一个循环过程,这个函数仍是挺有意思的
performUnitOfWork(nextUnitOfWork: Fiber) => Fiber | null ->
beginWork(current, workInProgress, nextRenderExpirationTime) // 这个函数开启一个work流程
复制代码
主要做用是根据Fiber对象的tag来对组件进行mount或update
function beginWork( current: Fiber | null, workInProgress: Fiber, renderExpirationTime: ExpirationTime, ): Fiber | null {
const updateExpirationTime = workInProgress.expirationTime; // 更新所需时间
if (
!hasLegacyContextChanged() &&
(updateExpirationTime === NoWork ||updateExpirationTime > renderExpirationTime)
) {
...
switch (workInProgress.tag) {
case IndeterminateComponent: { // 不肯定的组件类型
...
}
case FunctionalComponent: { // 函数类型组件
...
}
...
case ClassComponent: { // 对应咱们以前建立的组件 Simple
const Component = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
// 返回一个classComponent
return updateClassComponent(
current,
workInProgress,
Component,
unresolvedProps,
renderExpirationTime,
);
}
...
case HostRoot: // 对应根节点
return updateHostRoot(current, workInProgress, renderExpirationTime);
case HostComponent: // 对应 <h1 />
return updateHostComponent(current, workInProgress, renderExpirationTime);
case HostText: // 对应Simple test
return updateHostText(current, workInProgress);
... // 后面还有就不一一列举了,感兴趣能够本身看
}
复制代码
主要做用是对未初始化的组件进行初始化,对已初始化的组件进行更新和重用
function updateClassComponent( current: Fiber | null, workInProgress: Fiber, Component: any, nextProps, renderExpirationTime: ExpirationTime, ) {
...
if (current === null) {
if (workInProgress.stateNode === null) {
// 实例化类组件
constructClassInstance(
workInProgress, // Fiber更新进度标识
Component, // 组件
nextProps, // props
renderExpirationTime, // 所需时间
);
// 初始化mount
mountClassInstance(
workInProgress,
Component,
nextProps,
renderExpirationTime,
);
shouldUpdate = true;
} else {
// 若是已经建立实例,则重用
shouldUpdate = resumeMountClassInstance(
workInProgress,
Component,
nextProps,
renderExpirationTime,
);
}
} else {
shouldUpdate = updateClassInstance(
current,
workInProgress,
Component,
nextProps,
renderExpirationTime,
);
}
return finishClassComponent(
current,
workInProgress,
Component,
shouldUpdate,
hasContext,
renderExpirationTime,
);
}
...
}
复制代码
主要是挂载一些新的生命周期函数,除了比较熟悉的componentWillMount外,还有dev环境下的警告生命周期函数,以及16后才推出的getDerivedStateFromProps
function mountClassInstance( workInProgress: Fiber, ctor: any, newProps: any, renderExpirationTime: ExpirationTime, ): void {
...
if (__DEV__) {
if (workInProgress.mode & StrictMode) {
ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(
workInProgress,
instance,
);
ReactStrictModeWarnings.recordLegacyContextWarning(
workInProgress,
instance,
);
}
if (warnAboutDeprecatedLifecycles) {
ReactStrictModeWarnings.recordDeprecationWarnings(
workInProgress,
instance,
);
}
}
// 处理状态更新的操做
let updateQueue = workInProgress.updateQueue;
if (updateQueue !== null) {
processUpdateQueue(
workInProgress,
updateQueue,
newProps,
instance,
renderExpirationTime,
);
instance.state = workInProgress.memoizedState;
}
const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
if (typeof getDerivedStateFromProps === 'function') { // 挂载新的生命周期函数
applyDerivedStateFromProps(
workInProgress,
ctor,
getDerivedStateFromProps,
newProps,
);
instance.state = workInProgress.memoizedState;
}
if (
typeof ctor.getDerivedStateFromProps !== 'function' &&
typeof instance.getSnapshotBeforeUpdate !== 'function' &&
(typeof instance.UNSAFE_componentWillMount === 'function' ||
typeof instance.componentWillMount === 'function')
) {
// 若是沒有使用getDerivedStateFromProps就使用componentWillMount
callComponentWillMount(workInProgress, instance);
// 若是在这个生命周期中有状态更新,则立刻开始处理它
updateQueue = workInProgress.updateQueue;
if (updateQueue !== null) {
processUpdateQueue(
workInProgress,
updateQueue,
newProps,
instance,
renderExpirationTime,
);
instance.state = workInProgress.memoizedState;
}
}
if (typeof instance.componentDidMount === 'function') {
workInProgress.effectTag |= Update;
}
// 因此说使用getDerivedStateFromProps这个新的状态函数,第一次加载跟更新都会当即执行
}
复制代码
调用组件实例的render函数获取须要处理的子元素,并把子元素处理为Fiber类型,处理state和props
function finishClassComponent( current: Fiber | null, workInProgress: Fiber, Component: any, shouldUpdate: boolean, hasContext: boolean, renderExpirationTime: ExpirationTime, ) {
...
// 把子元素转换为Fiber类型,若是子元素为数组的時候,返回第一个Fiber类型子元素
reconcileChildren( // 感兴趣能够去github看看源码的说明
current,
workInProgress,
nextChildren,
renderExpirationTime,
);
// TODO: Restructure so we never read values from the instance.
// 处理state和props
memoizeState(workInProgress, instance.state);
memoizeProps(workInProgress, instance.props);
if (hasContext) {
invalidateContextProvider(workInProgress, Component, true);
}
// 返回Fiber类型的子元素
return workInProgress.child;
}
复制代码
workLoop遍历虚拟DOM树,调用performUnitOfWork对子元素进行处理。
function workLoop(isYieldy) {
if (!isYieldy) {
// 循环遍历整棵树
while (nextUnitOfWork !== null) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
} else {
// 一直遍历,直到这一次的处理时间用完
while (nextUnitOfWork !== null && !shouldYield()) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
}
}
复制代码
调用beginWork对子元素进行处理返回,没有新工做产生,调用completeUnitOfWork开始转换
function performUnitOfWork(workInProgress: Fiber): Fiber | null {
const current = workInProgress.alternate;
// 检查是否有其它工做须要展开
startWorkTimer(workInProgress);
...
let next;
// 判断是否在一个更新时间内
if (enableProfilerTimer) {
if (workInProgress.mode & ProfileMode) {
startProfilerTimer(workInProgress);
}
next = beginWork(current, workInProgress, nextRenderExpirationTime);
if (workInProgress.mode & ProfileMode) {
// 记录渲染时间
stopProfilerTimerIfRunningAndRecordDelta(workInProgress, true);
}
} else {
next = beginWork(current, workInProgress, nextRenderExpirationTime);
}
...
if (next === null) {
// 若是没有新的工做产生,则完成当前工做
next = completeUnitOfWork(workInProgress);
}
ReactCurrentOwner.current = null;
return next;
}
复制代码
主要做用是将Fiber节点元素转换为真实的DOM节点
function completeUnitOfWork(workInProgress: Fiber): Fiber | null {
while (true) {
const returnFiber = workInProgress.return; // 父节点
const siblingFiber = workInProgress.sibling; // 兄弟节点
if ((workInProgress.effectTag & Incomplete) === NoEffect) {
// 在一次渲染周期内
if (enableProfilerTimer) {
if (workInProgress.mode & ProfileMode) {
startProfilerTimer(workInProgress);
}
// 调用completeWork转换虚拟DOM
nextUnitOfWork = completeWork(
current,
workInProgress,
nextRenderExpirationTime,
);
if (workInProgress.mode & ProfileMode) {
// 更新渲染时间
stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false);
}
} else {
nextUnitOfWork = completeWork(
current,
workInProgress,
nextRenderExpirationTime,
);
}
let next = nextUnitOfWork;
stopWorkTimer(workInProgress); // 结束一个work
resetChildExpirationTime(workInProgress, nextRenderExpirationTime);
...
if (next !== null) { // 若是还有新的工做,return回去,继续执行
stopWorkTimer(workInProgress);
return next;
}
// 这个地方就不注释了,源码里面已经解释的足够清楚
if (
returnFiber !== null &&
// Do not append effects to parents if a sibling failed to complete
(returnFiber.effectTag & Incomplete) === NoEffect
) {
// Append all the effects of the subtree and this fiber onto the effect
// list of the parent. The completion order of the children affects the
// side-effect order.
if (returnFiber.firstEffect === null) {
returnFiber.firstEffect = workInProgress.firstEffect;
}
if (workInProgress.lastEffect !== null) {
if (returnFiber.lastEffect !== null) {
returnFiber.lastEffect.nextEffect = workInProgress.firstEffect;
}
returnFiber.lastEffect = workInProgress.lastEffect;
}
// If this fiber had side-effects, we append it AFTER the children's
// side-effects. We can perform certain side-effects earlier if
// needed, by doing multiple passes over the effect list. We don't want
// to schedule our own side-effect on our own list because if end up
// reusing children we'll schedule this effect onto itself since we're
// at the end.
const effectTag = workInProgress.effectTag;
// Skip both NoWork and PerformedWork tags when creating the effect list.
// PerformedWork effect is read by React DevTools but shouldn't be committed.
if (effectTag > PerformedWork) {
if (returnFiber.lastEffect !== null) {
returnFiber.lastEffect.nextEffect = workInProgress;
} else {
returnFiber.firstEffect = workInProgress;
}
returnFiber.lastEffect = workInProgress;
}
}
...
if (siblingFiber !== null) {
// 若是有兄弟节点,则返回一个兄弟节点
return siblingFiber;
} else if (returnFiber !== null) {
// 完成此次工做
workInProgress = returnFiber;
continue;
} else {
// 已经遍历到了根部
return null;
}
}
}else{
... // 感兴趣本身看
}
return null;
}
复制代码
根据Fiber节点类型进行处理,渲染真实DOM
function completeWork( current: Fiber | null, workInProgress: Fiber, renderExpirationTime: ExpirationTime, ): Fiber | null {
...
switch (workInProgress.tag) {
...
// 只看重点代码
case HostComponent: {
popHostContext(workInProgress);
const rootContainerInstance = getRootHostContainer();
const type = workInProgress.type;
if (current !== null && workInProgress.stateNode != null) {
// 更新
updateHostComponent(
current,
workInProgress,
type,
newProps,
rootContainerInstance,
);
if (current.ref !== workInProgress.ref) {
markRef(workInProgress);
}
} else {
...
const currentHostContext = getHostContext();
let wasHydrated = popHydrationState(workInProgress);
if (wasHydrated) {
...
} else {
// 建立并返回DOM元素
let instance = createInstance(
type,
newProps,
rootContainerInstance,
currentHostContext,
workInProgress,
);
// 添加节点
appendAllChildren(instance, workInProgress);
// 判断是否有其它的渲染器,进行标记
if (
finalizeInitialChildren(
instance,
type,
newProps,
rootContainerInstance,
currentHostContext,
)
) {
markUpdate(workInProgress);
}
workInProgress.stateNode = instance;
}
if (workInProgress.ref !== null) {
// 若是有ref,则须要调用
markRef(workInProgress);
}
}
break;
}
}
}
复制代码
在查看源码的过程当中,发现涉及异步的操做,都写上了unstable,而这些异步的操做,才是Fiber这个利器展示獠牙的时候,在将来的某个时刻,我会补上这部分的东西
ps: 有不对的地方欢迎斧正