Skip to content

Commit

Permalink
Merge pull request #6 from nparashar150/render/diffing
Browse files Browse the repository at this point in the history
Setup basic diffing on every render.
  • Loading branch information
nparashar150 authored Oct 6, 2022
2 parents b0e68d6 + bdb154f commit e745981
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 12 deletions.
123 changes: 119 additions & 4 deletions lib/render.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,124 @@
/**
*
* @param {HTMLElement} element
* @param {String} containerId
*
* @param {HTMLElement} element
* @param {String} containerId
*/
export const render = (element, containerId) => {
const root = document.getElementById(containerId);
root.appendChild(element);
if (!root.firstChild) {
return root.appendChild(element);
}
const oldNode = root.firstChild;
const newNode = element;

diff(oldNode, newNode);
};

/**
*
* @param {NodeList} oldNode
* @param {NodeList} newNode
*/
export const diff = (oldNode, newNode) => {
// Reference to nodeTypes: https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType

// If the old node is a text node and the new node is a text node
if (oldNode.nodeType === 3 && newNode.nodeType === 3) {
// If the text content is different
if (oldNode.textContent !== newNode.textContent) {
// Update the text content
oldNode.textContent = newNode.textContent;
}
}

// If the old node is a text node and the new node is not a text node
if (oldNode.nodeType === 3 && newNode.nodeType !== 3) {
// Replace the old node with the new node
oldNode.replaceWith(newNode);
}

// If the old node is not a text node and the new node is a text node
if (oldNode.nodeType !== 3 && newNode.nodeType === 3) {
// Replace the old node with the new node
oldNode.replaceWith(newNode);
}

// If the old node is not a text node and the new node is not a text node
if (oldNode.nodeType !== 3 && newNode.nodeType !== 3) {
// If the tag names are different
if (oldNode.tagName !== newNode.tagName) {
// Replace the old node with the new node
oldNode.replaceWith(newNode);
}

// If the tag names are the same
if (oldNode.tagName === newNode.tagName) {
// Update the attributes
updateAttributes(oldNode, newNode);

// Update the children
updateChildren(oldNode, newNode);
}
}
};

/**
*
* @param {NodeList} oldNode
* @param {NodeList} newNode
*/
export const updateAttributes = (oldNode, newNode) => {
// Reference to attributes: https://developer.mozilla.org/en-US/docs/Web/API/Element/attributes

// Get the old attributes
const oldAttributes = Array.from(oldNode.attributes);

// Get the new attributes
const newAttributes = Array.from(newNode.attributes);

// Remove the old attributes
oldAttributes.forEach((attribute) => {
oldNode.removeAttribute(attribute.name);
});

// Add the new attributes
newAttributes.forEach((attribute) => {
oldNode.setAttribute(attribute.name, attribute.value);
});
};

/**
*
* @param {NodeList} oldNode
* @param {NodeList} newNode
*/
export const updateChildren = (oldNode, newNode) => {
// Reference to childNodes: https://developer.mozilla.org/en-US/docs/Web/API/Node/childNodes

// Get the old children
const oldChildren = Array.from(oldNode.childNodes);

// Get the new children
const newChildren = Array.from(newNode.childNodes);

// If the new node has more children, add them
newChildren.forEach((child, index) => {
if (index >= oldChildren.length) {
oldNode.appendChild(child);
}
});

// If the new node has less children, remove them
oldChildren.forEach((child, index) => {
if (index >= newChildren.length) {
oldNode.removeChild(child);
}
});

// If the new node has the same number of children, update them
oldChildren.forEach((child, index) => {
if (index < newChildren.length) {
diff(child, newChildren[index]);
}
});
};
14 changes: 14 additions & 0 deletions lib/useState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
*
// * @param {*} initialState
* @param {*} _state
*/
export const useState = (initialState) => {
let _state = initialState;
const _setState = (newState) => {
if (_state === newState) return;
_state = newState;
return _state;
};
return [_state, _setState];
};
6 changes: 5 additions & 1 deletion public/index.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./css/styles.css">
<title>Document</title>
</head>
<body id="root">

<body>
<div id="root"></div>
</body>
<script async defer src="./js/own-react-bundle.js"></script>
<script async defer src="./js/useState.js"></script>

</html>
2 changes: 1 addition & 1 deletion public/js/own-react-bundle.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions public/js/useState.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ element["store"] = {};
document.body.appendChild(element);
element.innerText = "";

let root = document.body;
root.setAttribute("id", "root");
let root = document.getElementById("root");
// root.setAttribute("id", "root");

/**
*
Expand Down
8 changes: 6 additions & 2 deletions src/components/button/button.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ import "./button.css";

const Button = (children) => {
const handleClick = () => {
alert("Button clicked");
console.log("Button clicked");
};
return <button className="__btn" onClick={() => handleClick()}>{children}</button>;
return (
<button className="__btn" onClick={() => handleClick()}>
{children}
</button>
);
};

export default Button;
25 changes: 25 additions & 0 deletions src/global.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
*,
html,
body {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: monospace;
}

html,
body {
padding: 1rem;
}

html,
body,
h1,
h2,
h3,
h4,
h5,
h6,
p {
padding-bottom: 1rem;
}
58 changes: 56 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,72 @@
import OwnReact from "../lib/index";
import Button from "./components/button/button";
import "./global.css";

const App = () => {
return (
<div id="root2">
<Button>Click me</Button>
<h1>My First Own React App</h1>
<p>
<div className="testing">
<h1>My First Own React App with custom Babel and Webpack config</h1>
<p>This is another nesting level</p>
<Button>Click me</Button>
</div>
</p>
</div>
);
};
OwnReact.render(App(), "root");
const App2 = () => {
return (
<div id="root3">
<h1>My Second Own React App</h1>
<p>
<div className="testing">
<h1>My Second Own React App with custom Babel and Webpack config</h1>
<p>This is another nesting level</p>
<p>This is another nesting level</p>
<p>This is another nesting level</p>
<Button>Click me second</Button>
</div>
</p>
</div>
);
};

const App3 = () => {
return (
<div id="root4">
<h1>My Third Own React App</h1>
<p>
<div className="testing">
<h1>My Third Own React App with custom Babel and Webpack config</h1>
<p>This is another nesting level</p>
<p>This is another another nesting level</p>
<Button>Click me third</Button>
</div>
</p>
</div>
);
};

const App4 = () => {
return (
<div id="root4">
<h1>My Fourth Own React App</h1>
</div>
);
};

OwnReact.render(<App />, "root");

setTimeout(() => {
OwnReact.render(<App2 />, "root");
}, 5000);

setTimeout(() => {
OwnReact.render(<App3 />, "root");
}, 10000);

setTimeout(() => {
OwnReact.render(<App4 />, "root");
}, 15000);

0 comments on commit e745981

Please sign in to comment.