feat: allow to render function components
This commit is contained in:
parent
1dc675661a
commit
0f893d7341
3 changed files with 53 additions and 25 deletions
|
|
@ -124,6 +124,14 @@ function updateDom(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function commitDeletion(fiber: YarFiber, domParent: HTMLElement | Text) {
|
||||||
|
if (fiber.dom) {
|
||||||
|
domParent.removeChild(fiber.dom);
|
||||||
|
} else {
|
||||||
|
commitDeletion(fiber.child!, domParent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Actually commit the processed Fiber to the real DOM
|
* Actually commit the processed Fiber to the real DOM
|
||||||
* @param fiber - The Fiber Element to process
|
* @param fiber - The Fiber Element to process
|
||||||
|
|
@ -131,14 +139,23 @@ function updateDom(
|
||||||
function commitWork(fiber: YarFiber | null) {
|
function commitWork(fiber: YarFiber | null) {
|
||||||
if (!fiber) return;
|
if (!fiber) return;
|
||||||
|
|
||||||
const domParent = fiber.parent!.dom!;
|
// we can have fibers without dom nodes,
|
||||||
|
// so we search for the first parent with one
|
||||||
|
let parentFiber = fiber.parent!;
|
||||||
|
while (!parentFiber.dom) {
|
||||||
|
parentFiber = parentFiber.parent!;
|
||||||
|
}
|
||||||
|
|
||||||
|
const domParent = parentFiber.dom!;
|
||||||
|
|
||||||
switch (fiber.effectTag) {
|
switch (fiber.effectTag) {
|
||||||
case YarEffectTag.Placement:
|
case YarEffectTag.Placement:
|
||||||
domParent.appendChild(fiber.dom!);
|
if (fiber.dom) {
|
||||||
|
domParent.appendChild(fiber.dom);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case YarEffectTag.Deletion:
|
case YarEffectTag.Deletion:
|
||||||
domParent.removeChild(fiber.dom!);
|
commitDeletion(fiber, domParent);
|
||||||
break;
|
break;
|
||||||
case YarEffectTag.Update:
|
case YarEffectTag.Update:
|
||||||
updateDom(fiber.dom!, fiber.alternate!.props, fiber.props);
|
updateDom(fiber.dom!, fiber.alternate!.props, fiber.props);
|
||||||
|
|
@ -159,6 +176,26 @@ function commitRoot() {
|
||||||
WIP_ROOT = null;
|
WIP_ROOT = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateFunctionComponent(fiber: YarFiber) {
|
||||||
|
// the fiber from a function component doesn’t have a DOM node
|
||||||
|
// and the children come from running the function instead of getting them directly from the props
|
||||||
|
|
||||||
|
if (!(fiber.type instanceof Function)) return;
|
||||||
|
|
||||||
|
const children = [fiber.type(fiber.props)];
|
||||||
|
reconcileChildren(fiber, children);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateNativeComponent(fiber: YarFiber) {
|
||||||
|
if (!fiber.dom) {
|
||||||
|
// Create the actual dom element
|
||||||
|
fiber.dom = generateDomNode(fiber);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new fiber for each child
|
||||||
|
reconcileChildren(fiber, fiber.props.children);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process the Fiber Tree, this is a representation of the DOM
|
* Process the Fiber Tree, this is a representation of the DOM
|
||||||
* Since this process could be interrupted before the whole
|
* Since this process could be interrupted before the whole
|
||||||
|
|
@ -168,14 +205,12 @@ function commitRoot() {
|
||||||
* @param fiber - The Fiber to process
|
* @param fiber - The Fiber to process
|
||||||
*/
|
*/
|
||||||
function processFiber(fiber: YarFiber): YarFiber | undefined {
|
function processFiber(fiber: YarFiber): YarFiber | undefined {
|
||||||
if (!fiber.dom) {
|
if (fiber.type instanceof Function) {
|
||||||
// Create the actual dom element
|
updateFunctionComponent(fiber);
|
||||||
fiber.dom = generateDomNode(fiber);
|
} else {
|
||||||
|
updateNativeComponent(fiber);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new fiber for each child
|
|
||||||
reconcileChildren(fiber, fiber.props.children);
|
|
||||||
|
|
||||||
// Search for the new fiber that needs to be processed
|
// Search for the new fiber that needs to be processed
|
||||||
if (fiber.child) {
|
if (fiber.child) {
|
||||||
// return the first child of the current fiber
|
// return the first child of the current fiber
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
export type YarHTMLTagName = keyof React.JSX.IntrinsicElements | string;
|
export type YarHTMLTagName =
|
||||||
|
| keyof React.JSX.IntrinsicElements
|
||||||
|
| string
|
||||||
|
| Function;
|
||||||
|
|
||||||
export enum YarEffectTag {
|
export enum YarEffectTag {
|
||||||
Update,
|
Update,
|
||||||
|
|
|
||||||
20
src/main.tsx
20
src/main.tsx
|
|
@ -3,19 +3,9 @@ import { render } from "./lib/YarJS";
|
||||||
|
|
||||||
const root = document.querySelector<HTMLDivElement>("#app")!;
|
const root = document.querySelector<HTMLDivElement>("#app")!;
|
||||||
|
|
||||||
const rerender = (value: string) => {
|
function App(props) {
|
||||||
const onChange = (e: React.FormEvent<HTMLInputElement>) => {
|
return <h1>Hi {props.name}</h1>;
|
||||||
rerender(e.currentTarget.value);
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const element = (
|
const element = <App name="foo" />;
|
||||||
<div id="foo">
|
render(element, root);
|
||||||
<input type="text" onInput={onChange} value={value} />
|
|
||||||
<h2>Hello {value}</h2>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
render(element, root);
|
|
||||||
};
|
|
||||||
|
|
||||||
rerender("foo");
|
|
||||||
|
|
|
||||||
Reference in a new issue