Last active
December 14, 2016 18:25
-
-
Save rphansen91/77ecd4615aab7e340738d93905818a64 to your computer and use it in GitHub Desktop.
React From Scratch in ~100 lines
This file contains hidden or 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 Component from './toy-react' | |
import { div, img } from './toy-jsx' | |
class Nested extends Component { | |
render () { | |
const { src, style } = this.props; | |
return img({ src, style }) | |
} | |
} | |
class Example extends Component { | |
constructor (props) { | |
super(props) | |
this.state = { active: false } | |
} | |
setActive (active) { | |
this.setState({ active }) | |
} | |
render () { | |
const { srcs } = this.props; | |
const { active } = this.state; | |
return ( | |
div({ class: active?'activeClass':'inactiveClass', events: { | |
mouseenter: this.setActive.bind(this, true), | |
mouseleave: this.setActive.bind(this, false) | |
}}, [ ...srcs.map((src) => | |
Nested.create({ src }) | |
)]) | |
) | |
} | |
} | |
Example.create({ srcs: ['http://placehold.it/320x320', 'http://placehold.it/640x640'] }) | |
.place(document.getElementById('root')) |
This file contains hidden or 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
HTMLElement.prototype.attr = function (key, val) { | |
this.setAttribute(key, val); | |
} | |
HTMLElement.prototype.attrs = function (attrs) { | |
for (var attr in attrs) { | |
this.attr(attr, attrs[attr]); | |
} | |
} | |
HTMLElement.prototype.events = function (events) { | |
for (var event in events) { | |
this.addEventListener(event, events[event]) | |
} | |
} | |
HTMLElement.prototype.render = function (component, dom) { | |
if (!component) return; | |
if (Array.isArray(component)) return childRenderer.call(this, component, dom); | |
if (dom && dom.placed) return cmpUpdater.call(this, component, dom); | |
if (typeof component.place === 'function') return cmpRenderer.call(this, component, dom); | |
if (typeof component === 'string') return textRenderer.call(this, component, dom); | |
return elementRenderer.call(this, component, dom); | |
} | |
function childRenderer (children, dom) { | |
return children.map((el, i) => this.render(children[i], dom && dom[i])) | |
} | |
function cmpRenderer (component) { | |
// THIS IS A NESTED COMPONENT | |
return { placed: component.place(this) } | |
} | |
function cmpUpdater (component, dom) { | |
// THIS IS A PREVIOUSLY RENDERED NESTED COMPONENT | |
dom.placed.update(component.props); | |
return { placed: dom.placed }; | |
} | |
function textRenderer (text) { | |
this.innerHTML = text; | |
return text; | |
} | |
function elementRenderer (component, dom) { | |
let element; | |
const attrs = component.attrs || {}; | |
const events = attrs.events || {}; | |
if (dom && dom.element) { | |
element = dom.element; | |
element.attrs(attrs); | |
} else{ | |
element = document.createElement(component.tagName); | |
element.attrs(attrs); | |
element.events(events); | |
this.appendChild(element); | |
} | |
return { | |
element: element, | |
children: element.render(component.children, dom && dom.children), | |
remove: () => this.removeChild(element) | |
} | |
} |
This file contains hidden or 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
const h = (tagName) => (attrs, children) => ({ | |
tagName, | |
attrs, | |
children | |
}) | |
export const a = h('A'); | |
export const p = h('P'); | |
export const h1 = h('H1'); | |
export const h2 = h('H2'); | |
export const h3 = h('H3'); | |
export const h4 = h('H4'); | |
export const div = h('DIV'); | |
export const img = h('IMG'); | |
export const span = h('SPAN'); |
This file contains hidden or 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 './prototypes' | |
export default class Component { | |
constructor (props) { | |
this.props = props; | |
} | |
static create (props) { | |
// WE CAN INTERNALLY `new` THE INSTANCE | |
// ALLOWING US TO CALL UPDATE ON SUBSEQUENT RENDERS | |
return { | |
props, | |
place: (root) => new this(props).initialize(root), | |
} | |
} | |
initialize (root) { | |
// CALLED ONCE WHEN THE COMPONENT IS MOUNTED TO DOM | |
// SHOULD ADD ERRORS TO MAKE SURE THIS IS NOT CALLED DUPLICATE INSTANCES WILL BE ADDED TO DOM | |
this.root = root; | |
this.initiateRender(); | |
return this; | |
} | |
setState (state) { | |
this.state = Object.assign({}, this.state, state); | |
this.initiateRender(); | |
} | |
update (props) { | |
this.props = props || {}; | |
this.initiateRender(); | |
} | |
initiateRender () { | |
const html = this.render(); | |
const previousDOM = this.renderedDOM; | |
// NEED TO PASS IN THE PREVIOUS DOM SO WE DONT CREATE ALEADY CREATED ELEMENTS | |
this.renderedDOM = this.root.render(html, previousDOM); | |
} | |
render () { | |
console.warn('Must supply a render function'); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment