@skele/classic
Version:
Skele is an architectural framework that assists with building data-driven apps with React or React Native.
204 lines (143 loc) • 4.34 kB
Markdown
# Using Skele
# Hello World
## Importing
import { ui } from '@skele/classic';
import skele from '@skele/classic';
// what's inside
skele.ui
skele.read
skele.update
# Element UI
An element UI can be any React component that takes two props: `element` and `dispatch`.
It is registered using:
ui.register(<element kind>, <element>)
e.g.
UI.register('teaser', ({ element, dispatch }) => {
return (
<View>
<TouchableOpacity onPress={dispatch('ACTION_TYPE')} />
</View>
)
})
## Rendering children
Any element can render a sub element by:
UI.register(['navigation', 'stack'], ({ element, dispatch }) => {
return (
<View>
{ui.forElement(element.get('children').last())}
</View>
)
})
A list of children can be rendered using:
UI.register(['article'], ({ element, dispatch }) => {
return (
<View>
{ui.forElements(element.get('children'))}
</View>
)
})
## Dispatching Updates
The dispatch prop is used to dispatch an action. The action is identified by a simple string and its "namespace" is
local to the element itself.
It is not required that an update is registered for that specific action for the element. A container is able to
"catch" an action using pattern matching.
UI.register('teaser', ({ element, dispatch }) => {
return (
<View>
<TouchableOpacity onPress={dispatch('ACTION_TYPE')} />
</View>
)
})
# Actions, Updates, Sagas
An action is just a string identifying what needs to be performed on the state. When one triggers an action, one can
also supply additional parameters (payload) to the action that will be provided later on to the update or saga.
## Updates
Updates are registered in a similar way ui is registered, by using the element kind.
// update.register([any(), ofKind(['teaser']), 'bla']
updates.register('teaser'), (update, saga) => {
update('bla', element => element.set('bla', 1))
update('foo', element => element.set('foo', 2))
saga('x', function* () {
yield put(loading())
})
}
updates.register(['navigation', 'stack']), (update, saga) => {
// to be implemented in future
update([seq(any(), kindOf('teaser'), 'pop'] (stack, child) => stack.updateIn('children', cs => cs.append(child))
// to be implemented now
update('**/pop', stack => stack.updateIn('children', cs => cs.butLast())
saga('load', function *(url) {
}
});
updates.register([], (update, saga) => {
saga('read', (el, uri, subPath) => {
yield dispatch('read/Started', uri, subPath)
const readFn = reads.readForURI(uir);
const v = yield call(readFn, uri)
if ( v == success)
yield dispatch('read/Finished, uri, subPath, content)
else
yield dispatch('read/Error, uri, subPath, content)
})
update('read/Started', (el url.
update('read/Finished',
update('read/Error'
const updater = new Updater(initialState, saga)
.Case('bla'),
.Case('foo')
saga = function* () {
yield* fork(
takeEvery('x', function* () { })
}
# Reads
Reads are meant to standardize the way content is "read" into the application state and provide extension points for
transformations.
A read is in essence a saga.
reads.register(['scene'], ....)
read.
Invoking Reads:
1.
{
kind: 'scene',
content: {
kind: ['__read', 'article'],
uri: "http://example.com"
}
}
2.
{
kind: 'scene',
content: {
kind: ['__loading', 'article'],
uri: "http://example.com"
}
}
3.
{
kind: 'scene',
content: {
kind: 'article',
content: [
//...
]
}
}
4. error state
{
kind: 'scene',
content: {
kind: ['__error', 404, 'artcile],
message: "blkbklbkbkbk"
}
}
dispatch('read', "http://example.com", 'content', 'article')
dispatch({
type: 'READ',
uri: 'http://example.com',
where: 'content',
kind: ['article']
})
## Transformers
# Organizing an element
# Configuration
# Engine