英文
- ReCap 回顾
- as compared to 相比于
文章
HostConfig
我们必须在HostConfig中实现所有必须的平台特定函数,这些函数有很多,但是我们不用全部实现,在初始化渲染的时候的reconciler会调用hostConfig中不同的函数。
Initial render
根据报错,先补全缺失的函数,确保intial render可以通过
const HostConfig = {
supportsMutation: true,
getRootHostContext: function (...args) {
console.log("getRootHostContext", ...args);
},
getChildHostContext: function (...args) {
console.log("getChildHostContext", ...args);
},
shouldSetTextContent: function (...args) {
console.log("shouldSetTextContent", ...args);
},
createTextInstance: function (...args) {
console.log("createTextInstance", ...args);
},
createInstance: function (...args) {
console.log("createInstance", ...args);
},
appendInitialChild: function (...args) {
console.log("appendInitialChild", ...args);
},
finalizeInitialChildren: function (...args) {
console.log("finalizeInitialChildren", ...args);
},
prepareForCommit: function (...args) {
console.log("prepareForCommit", ...args);
},
resetAfterCommit: function (...args) {
console.log("resetAfterCommit", ...args);
},
detachDeletedInstance: function (...args) {
console.log("detachDeletedInstance", ...args);
},
clearContainer: function (...args) {
console.log("clearContainer", ...args);
},
removeChildFromContainer: function (...args) {
console.log("removeChildFromContainer", ...args);
},
appendChildToContainer: function (...args) {
console.log("appendChildToContainer", ...args);
},
};
按照博客的补全所有方法,还是有一个appendAllChild方法没有检测到,哪怕在HostConfig里补上还是会报这个问题,最后在reconciler文档中找到一个配置supportsMutation,在Dom中拥有appendChild和removeChild的方法,将其配置为true.链接 最后补全所有函数
const HostConfig = {
supportsMutation: true,
/**
* 让你和其他函数分享一些context
* @param {*} nextRootInstance 你定义的rootDom
*/
getRootHostContext: function (nextRootInstance) {
console.log("getRootHostContext", nextRootInstance);
let rootContext = {};
return rootContext;
},
/**
*从父级节点访问上下文,给子级节点传递上下文
* @param {...any} parentContext 父级节点的上下文 fiberType: fiber的类型 rootInstance: rootDom
*/
getChildHostContext: function (parentContext, fiberType, rootInstance) {
console.log("getChildHostContext", parentContext, fiberType);
let context = {};
return context;
},
/**
* 如果函数返回 true,则文本将在宿主元素内创建,并且不会单独创建新的文本元素。
* 如果返回 true,则接下来调用的是当前元素的 createInstance方法, 并且遍历将在此节点处停止(不会遍历此元素的子元素)。
* 如果返回 false,子元素将会继续调用getChildHostContext与shouldSetTextContent。它会一直持续到 shouldSetTextContent 返回 true 或者递归到树的最后一个node节点(通常是文本节点)。当它到达最后一个叶子节点时,它将调用 createTextInstance方法。
* @param {...any} type fiber的类型 props: 宿主元素的props
*/
shouldSetTextContent: function (type, props) {
console.log("shouldSetTextContent", type, props);
return false;
},
/**
* 这个函数用于创建文本节点
* @param {*} newText 包含的文本内容
* @param {*} rootContainerInstance 跟节点
* @param {*} currentHostContext 宿主元素上下文
* @param {*} workInProgress txt节点的fiber
* @returns 一个文本节点
*/
createTextInstance: function (
newText,
rootContainerInstance,
currentHostContext,
workInProgress
) {
console.log(
"createTextInstance",
newText,
rootContainerInstance,
currentHostContext,
workInProgress
);
return document.createTextNode(newText);
},
/**
* createInstance被所有的host nodes调用(除了叶子文本节点)
* @param {*} type
* @param {*} newProps
* @param {*} rootContainerInstance
* @param {*} currentHostContext
* @param {*} workInProgress
* @returns 一个宿主元素
*/
createInstance: function (
type,
newProps,
rootContainerInstance,
currentHostContext,
workInProgress
) {
console.log(
"createInstance",
type,
newProps,
rootContainerInstance,
currentHostContext,
workInProgress
);
const element = document.createElement(type);
element.className = newProps.className || "";
element.style = newProps.style;
return element;
},
/**
* 将子节点插入父节点
* @param {*} parent
* @param {*} child
*/
appendInitialChild: function (parent, child) {
console.log("appendInitialChild", parent, child);
parent.appendChild(child);
},
/**
* 在 react native 渲染器的情况下,这个函数除了返回 false 什么都不做。
* 在 react-dom 的情况下,这会添加默认的 dom 属性,例如事件侦听器等。为了实现某些input元素的autofocus(autofocus只能在渲染完成后发生),react-dom 发送返回类型为 true
* @param {*} instance appendInitialChild 之后的 dom 元素
* @param {*} type
* @param {*} newProps
* @param {*} rootContainerInstance
* @param {*} currentHostContext
* @returns 决定是否需要调用该节点的commitMount
*/
finalizeInitialChildren: function (
instance,
type,
newProps,
rootContainerInstance,
currentHostContext
) {
console.log(
"finalizeInitialChildren",
instance,
type,
newProps,
rootContainerInstance,
currentHostContext
);
return newProps.autofocus;
},
/**
* 完成制作内存渲染树时将会执行该函数
* @param {*} rootContainerInstance
*/
prepareForCommit: function (rootContainerInstance) {
console.log("prepareForCommit", rootContainerInstance);
},
/**
* 内存渲染树被插入到跟节点后执行该函数,这里可以重新启用prepareForCommit中禁用的事件
* @param {*} rootContainerInstance
*/
resetAfterCommit: function (rootContainerInstance) {
console.log("resetAfterCommit", rootContainerInstance);
},
detachDeletedInstance: function (...args) {
console.log("detachDeletedInstance", ...args);
},
clearContainer: function (container) {
console.log("clearContainer", container);
container.innerHtml = "";
},
removeChildFromContainer: function (parent, child) {
console.log("removeChildFromContainer", parent, child);
parent.removeChild(child);
},
/**
* 将我们的内存树挂载到root div。但是这个函数只有在我们设置了 supportsMutation:true 时才有效。
*/
appendChildToContainer: function (parent, child) {
console.log("appendChildToContainer", parent, child);
parent.appendChild(child);
},
commitMount: (domElement, type, newProps, fiberNode) => {
domElement.focus();
},
};
最后,通过我们自定义的渲染器渲染出了hello world,这里出现了一个问题,world的蓝色样式并没有加上,因为文章中作者在createInstance函数中element.style=style直接赋值,而jsx中react是对象,原生dom不识别这种写法,所以我们需要对style进行转换一下
const styleObj = newProps.style || {};
let str = "";
for (let key in styleObj) {
str += `${key}:${styleObj[key]};`;
}
element.style = str;