Last active
May 5, 2020 10:54
-
-
Save jeffmcmahan/8d10c579df82d32b13e2f449d1575c95 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {reconcile} from './utils/reconcile.mjs' | |
import {bar} from './bar-component.mjs' | |
import {baz} from './baz-component.mjs' | |
export const app = () => { | |
/// This is a component; it creates a node, sets some invariant properties on | |
/// that node (e.g., handler functions, sometimes CSS classes, &c.). | |
/// => any => Object | |
const node = document.createElement('div') | |
node.onclick = evt => { | |
evt.stopPropagation() | |
alert('Foo!') | |
} | |
node.oncontextmenu = evt => { | |
evt.preventDefault() | |
evt.stopPropagation() | |
} | |
return props => { | |
/// Here's our update function, which generates an object whose properties | |
/// will be applied to the node if they differ from it. | |
/// => Object | |
let className = 'foo' | |
if (props.inactive) { | |
className += ' inactive' | |
} | |
// Okay, let's return our partial state description: | |
return { | |
node, | |
className, | |
childNodes: [ | |
bar(props), // These components are of the same form as the parent. | |
baz(props) | |
] | |
} | |
} | |
} | |
// (1) Let's create the app component: | |
const myApp = app() | |
// (2) Let's call it to get a state object with a DOM node reference: | |
const appState = myApp({inactive: false}) | |
// (3) Let's apply the state properties to the app DOM node: | |
reconcile(appState) | |
// (4) Let's mount the app to the DOM: | |
document.body.append(appState.node) | |
// And here's our global render function: | |
window.render = props => reconcile(myApp(props)) | |
// For example: | |
render({inactive: true}) // className in DOM is now 'foo inactive' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The logic of a
reconcile
function is veerrrrryy roughly:Probably my favorite thing about this is that
reconcile
is different in like every project I do; sometimes it's 100% asynchronous with all kinds of hooks for doing complex animations from within component code, and sometimes is plain Jane - much closer to the above, taking maybe 50-60 lines to cover the ground without frills. I agree with Knuth in hating "toolkits" that don't give you this kind re-editability, which is to say, freedom.