@skele/classic
Version:
Skele is an architectural framework that assists with building data-driven apps with React or React Native.
133 lines (109 loc) • 3.17 kB
JavaScript
import * as R from 'ramda'
import React from 'react'
import PropTypes from 'prop-types'
import * as Kernel from '../kernel'
import * as Subsystem from '../subsystem'
import { defaultSubsystems } from '../core'
import memoizeOne from '../impl/memoize-one'
class EntryPointImpl extends React.Component {
static propTypes = {
kernel: PropTypes.shape({
subscribe: PropTypes.function,
query: PropTypes.fuction,
dispatch: PropTypes.function,
}).isRequired,
keyPath: PropTypes.oneOfType([
PropTypes.arrayOf(
PropTypes.oneOfType([PropTypes.string, PropTypes.number])
),
PropTypes.string,
]),
}
static defaultProps = {
keyPath: [],
}
constructor(props, context) {
super(props, context)
this._unsubscribe = this.props.kernel.subscribe(this._reRender.bind(this))
}
componentDidUpdate(prevProps) {
if (
this.props.kernel !== prevProps.kernel ||
!R.equals(this.props.keyPath, prevProps.keyPath)
) {
if (this._unsubscribe) this._unsubscribe()
this._unsubscribe = this.props.kernel.subscribe(this._reRender.bind(this))
}
}
componentWillUnmount() {
if (this._unsubscribe) this._unsubscribe()
}
_reRender() {
this.forceUpdate()
}
render() {
const kernel = this.props.kernel
return kernel.subsystems.ui.uiFor(kernel.query(this.props.keyPath))
}
}
const buildImpl = memoizeOne(kernel => {
const entryPointMixins = getCombinedMixins(kernel.subsystemSequence)
return R.isEmpty(entryPointMixins)
? EntryPointImpl
: R.reduce((C, M) => M(C), EntryPointImpl, entryPointMixins)
})
export class EntryPoint extends React.Component {
static propTypes = EntryPointImpl.propTypes
constructor(props, context) {
super(props, context)
}
render() {
const Impl = buildImpl(this.props.kernel)
return <Impl {...this.props} />
}
}
const buildKernel = memoizeOne(
(initState, subsystems, additionalSubsystems, customMiddleware, config) => {
subsystems = subsystems || defaultSubsystems
if (additionalSubsystems != null) {
subsystems = subsystems.concat(additionalSubsystems)
}
if (customMiddleware != null) {
subsystems = subsystems.concat(
R.map(Subsystem.fromMiddleware, customMiddleware)
)
}
return Kernel.create(subsystems, initState, config)
}
)
export class Engine extends React.Component {
static propType = {
initState: PropTypes.object.isRequired,
customMiddleware: PropTypes.arrayOf(PropTypes.func),
subsystems: PropTypes.arrayOf(PropTypes.object),
additionalSubsystems: PropTypes.arrayOf(PropTypes.object),
config: PropTypes.object,
}
constructor(props, context) {
super(props, context)
}
render() {
const {
initState,
customMiddleware,
subsystems,
additionalSubsystems,
config,
} = this.props
const kernel = buildKernel(
initState,
subsystems,
additionalSubsystems,
customMiddleware,
config
)
return <EntryPoint kernel={kernel} keyPath={[]} />
}
}
const getCombinedMixins = R.chain(Subsystem.engineMixins)