cycle-channel
Cycle.js is a fantastic framework for handling the cyclical stream-based nature of UI, but it doesn't give that full-framework feeling by itself. In comes cycle-channel, explained by the below image:
This means that cycle-channel is a single pipeline of driver sources to driver sinks. The core point of cycle-channel (and the sublibraries) is to provide a unified interface for data and actions and their intertwined behavior. This kind of logic often gets written by hand and instead I prefer to have something stable.
Usage
For this example I've removed the import
statements for anything that isn't really important.
import {channel} from "cycle-channel"
import {stateDriver} from "cycle-channel"
import {dataDriver} from "cycle-channel"
import {viewEventSignals} from "cycle-channel-dom"
import {networkResponseSignals} from "cycle-channel-http"
import {storageReadSignals} from "cycle-channel-storage"
import intent from "snabbdom-intent"
const intents = {
onChangeSearch: intent({change: ["updateFormField", "fetchSearchResult"]})
}
const render = ({state}) => {
const withSearch = intents.onChangeSearch({
form: "search",
field: "query",
})
return main({
children: [
h1({children: "Google"}),
input(withSearch({children: state.ephemeral.forms.search.query})),
p({children: "See below for the results"}),
ul({children: mapValues((result) => li({children: result.title}))(state.resources.results)}),
],
})
}
const application = ({view, network, storage}) => {
return channel({
signals: [
viewEventSignals(view),
networkResponseSignals(network),
storageReadSignals(storage),
],
initialState: {},
reactions: {
updateFormField: (state) => ({event, form, field}) => {
return mergeDeepRight(
state
)(
recordFrom(["ephemeral", "forms", form, field])(event.target.value)
)
},
mergeResources: (state) => ({data}) => {
return mergeDeepRight(
state
)({
resources: treeify([groupBy(keyChain(["attributes", "type"])), indexBy(key("id"))])(data)
})
},
},
transformers: {
fetchSearchResult: (state) => ({event}) => {
return {
driver: "network",
data: {
method: "GET",
url: `https://api.example.com/search?query=${event.target.value}`,
headers: {Authorization: `Basic ${state.ephemeral.authorization}`},
},
}
},
},
drains: {view: stateDriver(render)},
vents: {
network: dataDriver(),
storage: dataDriver(),
},
})
}
const drivers = {
view: makeDOMDriver("body"),
network: makeHTTPDriver(),
storage: storageDriver(),
}
run(application, drivers)