0.28.0
Breaking changes
The store/component state is now passed to the connect function, not to each individual message handler.
Before:
const click = Message<MouseEvent>('click')
function connect({ on }: ConnectParams<Props, State>) {
on(click, (state, evt) => ({ ...state, clicked: true }))
}After:
const click = Message<MouseEvent>('click')
function connect({ on, state }: ConnectParams<Props, State>) {
on(click, evt => ({ ...state(), clicked: true }))
}The state parameter passed to the connect function is an Observable (just like props). That means you can now derive state changes from... state changes! Of course, just like with Message sending, you have to break the recursion at some point.
For instance, given a Select component, you may want to listen to click events on the body to close the currently opened dropdown, but only if the Select is currently opened:
const click = Message<MouseEvent>('click')
function connect({ on, state }: ConnectParams<Props, State>) {
const clicksOutsideDropdown = state
.map(s => s.opened)
.distinct()
.flatmapLatest(opened => opened
? Observable.fromEvent('mousedown', document.body)
: Observable())
on(clicksOutsideDropdown , evt => ({ ...state(), opened: false }))
}It can also be used to recompute dependent pieces of state in a single place (eg. a list and its dependent filtered/sorted list)
Message type simplification
Before, it was very confusing to know when to declare that a component expected its parent to provide it with a Message or a DefaultMessage. The types are now streamlined and conveniently packaged in the Message namespace:
Before:
NoArgMessage
DefaultNoArgMessage
Message<MouseEvent>
DefaultMessage<MouseEvent>
Message<[string, MouseEvent]>
DefaultMessage<[string, MouseEvent]>After:
Message.NoPayload
Message.OnePayload<MouseEvent>
Message.TwoPayloads<string, MouseEvent>For messages with two payloads, you no longer need to expect an Array inside your message handlers, just two distinct parameters.
Message creation is unchanged.
Non breaking enhancements
connectToStore
A component can connect to a store manually by reading the store's piece of data inside initState and keeping it updated by subscribing to the store's state inside connect. This will still work but is a bit cumbersome in the most simple cases as it duplicates the Store's state mapping logic and forces the component to treat a Store state piece as internal state even though it could be a regular props.
Enter connectToStore, inspired by redux: README
log
You can shut logs off for a particular component. This is mainly useful for boring higher order components:
function MyComponent() {
return Component<Props, State>({ name: 'myComponent', log: false, initState, connect, render })
}example update
The example was updated to be simpler (and errr... easier to maintain)