Skip to content

Commit 47e97f3

Browse files
committed
Added props and events extractor
1 parent c1f62c0 commit 47e97f3

6 files changed

Lines changed: 68 additions & 3 deletions

File tree

src/components/component.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,23 @@ import { patchDOM } from "../patch-dom";
44
import { DOM_TYPES, extractChildren } from "../h";
55
import { hasOwnProperty } from "../utils/objects";
66

7-
// A factory function that, given a render() function,
8-
// creates a component class that uses that function to render its view.
97
export function defineComponent({ render, state, ...methods }) {
108
class Component {
119
#isMounted = false;
1210
#vdom = null;
1311
#hostEl = null;
12+
#eventsHandlers = null;
13+
#parentComponent = null;
1414

15-
constructor(props = {}) {
15+
constructor(
16+
props = {},
17+
eventHandlers = {},
18+
parentComponent = null,
19+
) {
1620
this.props = props;
1721
this.state = state ? state(props) : {};
22+
this.#eventsHandlers = eventHandlers;
23+
this.#parentComponent = parentComponent;
1824
}
1925

2026
get elements() {
@@ -52,6 +58,13 @@ export function defineComponent({ render, state, ...methods }) {
5258
this.#patch(); // To reflect the changes in the DOM
5359
}
5460

61+
updateProps(props) {
62+
// TODOS: By comparing the old new prop objects, we can avoid patching and
63+
// TODOS:the component—and all its subcomponents—if its props haven’t changed (deep-equal package)
64+
this.props = { ...this.props, ...props }; // Merge new and old props.
65+
this.#patch(); // Re-render
66+
}
67+
5568
render() {
5669
// returns its view as a virtual DOM based on the state.
5770
return render.call(this);

src/components/componentExample.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { defineComponent } from "./component";
2+
import { hElement } from "../h";
3+
4+
const List = defineComponent({
5+
render() {
6+
const { todos } = this.props;
7+
return hElement('ul', {}, todos.map((todo) => hElement(ListItem, { todo })));
8+
}
9+
})
10+
11+
const ListItem = defineComponent({
12+
render() {
13+
const { todo } = this.props;
14+
return hElement('li', {}, [todo])
15+
}
16+
})

src/destroy-dom.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ export function destroyDOM(vdom) {
1717
removeFragmentNodes(vdom);
1818
break;
1919
}
20+
case DOM_TYPES.COMPONENT: {
21+
vdom.component.unmount(); // Calls the node's component instance unmount method
22+
break;
23+
}
2024
default: {
2125
throw new Error(`Can't destroy DOM of type: ${type}`);
2226
}

src/mount-dom.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { DOM_TYPES } from './h';
22
import { setAttributes } from './attributes';
33
import { addEventListeners } from './events';
4+
import { extractPropsAndEvents } from './utils/props';
45

56
export function mountDOM(
67
vdom,
@@ -31,6 +32,17 @@ export function mountDOM(
3132
}
3233
}
3334

35+
function createComponentNode(vdom, parentEl, index, hostComponent)
36+
{
37+
const Component = vdom.tag;
38+
const { props, events } = extractPropsAndEvents(vdom);
39+
const component = new Component(props, events, hostComponent);
40+
41+
component.mount(parentEl, index);
42+
vdom.component = component; // Save component's first DOM Element in the Virtual Node.
43+
vdom.el = component.firstElement;
44+
}
45+
3446
function createTextNode(vdom, parentElement, index) {
3547
const { value } = vdom;
3648
const textNode = document.createTextNode(value);

src/patch-dom.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
setStyle
1313
} from './attributes';
1414
import { addEventListener } from './events';
15+
import { extractPropsAndEvents } from './utils/props';
1516

1617

1718
export function patchDOM(
@@ -39,12 +40,26 @@ export function patchDOM(
3940
patchElement(oldVdom, newVdom, hostComponent);
4041
break;
4142
}
43+
case DOM_TYPES.COMPONENT: {
44+
patchComponent(oldVdom, newVdom);
45+
break;
46+
}
4247
}
4348
patchChildren(oldVdom, newVdom, hostComponent);
4449

4550
return newVdom;
4651
}
4752

53+
function patchComponent(oldVdom, newVdom) {
54+
const { component } = oldVdom; // Extracts the component instance from the old virtual node
55+
const { props } = extractPropsAndEvents(newVdom);
56+
57+
component.updateProps(props);
58+
59+
newVdom.component = component; // Save component instance in the new virtual node
60+
newVdom.el = component.firstElement; // Save the component instance in the new virtual node
61+
}
62+
4863
function patchText(oldVdom, newVdom) {
4964
const el = oldVdom.el;
5065
const { value: oldValue } = oldVdom;

src/utils/props.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export function extractPropsAndEvents(vdom) {
2+
const { on: events = {}, ...props } = vdom.props;
3+
4+
return { props, events };
5+
}

0 commit comments

Comments
 (0)