feat: allow to render function components

This commit is contained in:
Alexander Navarro 2024-06-26 11:27:31 -04:00
parent 1dc675661a
commit 0f893d7341
Signed by untrusted user who does not match committer: anavarro
GPG key ID: 6426043E9FA3E3B5
3 changed files with 53 additions and 25 deletions

View file

@ -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
* @param fiber - The Fiber Element to process
@ -131,14 +139,23 @@ function updateDom(
function commitWork(fiber: YarFiber | null) {
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) {
case YarEffectTag.Placement:
domParent.appendChild(fiber.dom!);
if (fiber.dom) {
domParent.appendChild(fiber.dom);
}
break;
case YarEffectTag.Deletion:
domParent.removeChild(fiber.dom!);
commitDeletion(fiber, domParent);
break;
case YarEffectTag.Update:
updateDom(fiber.dom!, fiber.alternate!.props, fiber.props);
@ -159,6 +176,26 @@ function commitRoot() {
WIP_ROOT = null;
}
function updateFunctionComponent(fiber: YarFiber) {
// the fiber from a function component doesnt 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
* Since this process could be interrupted before the whole
@ -168,14 +205,12 @@ function commitRoot() {
* @param fiber - The Fiber to process
*/
function processFiber(fiber: YarFiber): YarFiber | undefined {
if (!fiber.dom) {
// Create the actual dom element
fiber.dom = generateDomNode(fiber);
if (fiber.type instanceof Function) {
updateFunctionComponent(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
if (fiber.child) {
// return the first child of the current fiber

View file

@ -1,4 +1,7 @@
export type YarHTMLTagName = keyof React.JSX.IntrinsicElements | string;
export type YarHTMLTagName =
| keyof React.JSX.IntrinsicElements
| string
| Function;
export enum YarEffectTag {
Update,

View file

@ -3,19 +3,9 @@ import { render } from "./lib/YarJS";
const root = document.querySelector<HTMLDivElement>("#app")!;
const rerender = (value: string) => {
const onChange = (e: React.FormEvent<HTMLInputElement>) => {
rerender(e.currentTarget.value);
};
function App(props) {
return <h1>Hi {props.name}</h1>;
}
const element = (
<div id="foo">
<input type="text" onInput={onChange} value={value} />
<h2>Hello {value}</h2>
</div>
);
render(element, root);
};
rerender("foo");
const element = <App name="foo" />;
render(element, root);