Last active
June 16, 2016 06:42
-
-
Save resistdesign/16230bc92b13b72e3b429341b757678b to your computer and use it in GitHub Desktop.
A simple React Flux implementation with Dependency Injection for Components created by a React Router createElement handler.
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 React, { Component } from 'react'; | |
export default class FluxDI { | |
static validateContextName(name){ | |
if(typeof name !== 'string'){ | |
throw new Error('`name` must be a string.'); | |
} | |
} | |
static validateContext(context){ | |
if(!(context instanceof Map)){ | |
throw new Error('`context` must be a Map.'); | |
} | |
} | |
contexts = {}; | |
constructor(contexts){ | |
if(contexts instanceof Object){ | |
this.contexts = contexts; | |
} | |
} | |
ensureContexts(){ | |
if(!(this.contexts instanceof Object)){ | |
this.contexts = {}; | |
} | |
} | |
getContext(name){ | |
FluxDI.validateContextName(name); | |
this.ensureContexts(); | |
if(!(this.contexts[name] instanceof Map)){ | |
const newContexts = { ...this.contexts }; | |
newContexts[name] = new Map(); | |
this.contexts = newContexts; | |
} | |
return this.contexts[name]; | |
} | |
setContext(name, context){ | |
FluxDI.validateContextName(name); | |
FluxDI.validateContext(context); | |
this.ensureContexts(); | |
const newContexts = { ...this.contexts }; | |
newContexts[name] = context; | |
} | |
removeContext(name){ | |
FluxDI.validateContextName(name); | |
this.ensureContexts(); | |
const newContexts = { ...this.contexts }; | |
delete newContexts[name]; | |
this.contexts = newContexts; | |
} | |
cloneMap(map){ | |
if(map instanceof Map){ | |
const newMap = new Map(); | |
map.forEach((value, key) => { | |
newMap.set(key, value); | |
}); | |
return newMap; | |
} | |
} | |
/** | |
* Add a component to a context. | |
*/ | |
addComponent(contextName, component, props, serviceMap, eventMap, immediateMap, contextPropMap){ | |
const context = this.getContext(contextName); | |
const getComponent = (ViewComponent, contextProps) => { | |
if(component instanceof Function){ | |
const initialState = { ...props }; | |
if(contextPropMap instanceof Object && contextProps instanceof Object){ | |
for(const k in contextPropMap){ | |
if(contextPropMap.hasOwnProperty(k)){ | |
const targetProp = contextPropMap[k]; | |
if(contextProps.hasOwnProperty(targetProp)){ | |
initialState[k] = contextProps[targetProp]; | |
} | |
} | |
} | |
} | |
class FluxDIComponent extends Component { | |
constructor(){ | |
super(); | |
} | |
componentDidMount(){ | |
if(serviceMap instanceof Object){ | |
const newState = {}; | |
if(eventMap instanceof Object){ | |
for(const k in eventMap){ | |
if(eventMap.hasOwnProperty(k)){ | |
const targetProp = eventMap[k]; | |
const serviceMethod = serviceMap[targetProp]; | |
if(serviceMethod instanceof Function){ | |
newState[k] = async (...args) => { | |
const data = await serviceMethod.apply(null, args); | |
const updatedState = {}; | |
updatedState[targetProp] = data; | |
this.setState(updatedState); | |
}; | |
} | |
} | |
} | |
} | |
if(immediateMap instanceof Object){ | |
for(const k in immediateMap){ | |
if(immediateMap.hasOwnProperty(k)){ | |
const callWith = immediateMap[k]; | |
const args = callWith instanceof Function ? callWith(contextProps) : [ ...(callWith || []) ]; | |
const serviceMethod = serviceMap[k]; | |
if(serviceMethod instanceof Function){ | |
const immediateCall = async () => { | |
const data = await serviceMethod.apply(null, args); | |
const updatedState = {}; | |
updatedState[k] = data; | |
this.setState(updatedState); | |
}; | |
immediateCall(); | |
} | |
} | |
} | |
} | |
this.setState(newState); | |
} | |
} | |
state = initialState; | |
render(){ | |
return ( | |
<ViewComponent | |
{ ...this.state } | |
/> | |
); | |
} | |
} | |
return FluxDIComponent; | |
} | |
}; | |
context.set(component, getComponent); | |
} | |
/** | |
* Remove a component from a context. | |
*/ | |
removeComponent(contextName, component){ | |
const context = this.getContext(contextName); | |
const newContext = this.cloneMap(context); | |
newContext.unset(component); | |
this.setContext(contextName, newContext); | |
} | |
/** | |
* Get a FluxDI component. | |
*/ | |
getComponent(contextName, component, props){ | |
const context = this.getContext(contextName); | |
const getComponent = context.get(component); | |
if(getComponent instanceof Function){ | |
const FluxDIComponent = getComponent(component, props); | |
return ( | |
<FluxDIComponent/> | |
); | |
}else{ | |
return ( | |
<component | |
{ ...props } | |
/> | |
); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment