msg
v1.0.0
Published
Elmish Message data structure
Downloads
251
Readme
MSG: Message Signal Generator
Exports a single function which takes an object of name -> function pairs and contructs a data structure which can be used to make an Elm Architecture / Redux style app. Inspired by union-type.
295 bytes. No dependencies.
What it does
npm i -S msg
import Message from 'msg'
const Route = ( model, path ) => { model.route = path; return model }
const Select = ( model, name ) => { model.selected = name; return model }
const Saved = ( model, name ) => { model.saved = true; return model }
const actions = { Route, Select, Saved }
const Action = Message( actions )
console.log( Action )
console.log(Action.Route( '/' ))
Action.isPrototypeOf( Action.Route() ) //=> true
Action.isPrototypeOf( Action.Route ) //=> false
Message.prototype.isPrototypeOf( Action.Route() ) //=> true
Action.Route() instanceof Message //=> true
What it's for
Define effects
const Effect = Message(
{ Save: ( message$, index ) => {
localStorage.setItem( 'selected', index )
return Action.Saved()
}})
Initialise model
const init = () =>
({ route: '/'
, selected: localStorage.getItem( 'selected' )
, names: [ 'Johnathan Best', 'Adonai Reynolds', 'Kasandra Ursler', 'Honora Bognár' ]
, saved: false
})
Define the view Import update as render so it doesn't clash with our model update function
import yo, { update as render } from 'yo-yo'
const view = message$ => model => yo`
<div>
<button onclick=${ e => message$( Effect.Save( model.selected ))}>Save</button>
<ul>${ model.names.map(( name, index ) => yo`
<li onclick=${ e => message$( Action.Select( index ))}>
${ model.selected == index ? name.toUpperCase() : name }
</li>`)}
</ul>
${ model.saved ? 'Saved!' : null }
</div>
`
Define flyd streams. Flyd has a good explanation in its README.
const update = ( model, action ) => action.value( model, ...action.args )
const instanceOf = type => msg =>
type.isPrototypeOf( msg )
import { stream, scan, map } from 'flyd'
import filter from 'flyd/module/filter'
const message$ = stream()
const action$ = filter( instanceOf( Action ), message$ )
const model$ = scan( update, init(), action$ ) // Contains the entire state of the application
const node$ = map( view( message$ ), model$ ) // Stream of DOM nodes to patch the document
message$
is short for messageStream. message$
is a function which takes one or zero arguments. If you pass a value to action$
, that becomes the value returned next time message$
is called with no argument.
message$( 'example' )
message$() // => 'example'
The scan
function is like reduce. It returns a new stream based on manipulating the stream passed as its third argument. The second argument is the initial value of the returned stream. Each time something is pushed onto action$
by calling action$( something )
, scan
runs update
and passes it two arguments. 1: model
- the last value passed to model$
. 2: action
- the last value passed to action$
. The value returned by update
becomes the new value of model$
.
const container = document.querySelector( '#app' )
scan( render, container, node$ )
const effect$ = filter( instanceOf( Effect ), message$ )
map( effect => message$( effect.value( ...effect.args )), effect$ )