Cycle’s core abstraction is Human-Computer Interaction modelled as an interplay between two pure functions: human()
and computer()
. The computer outputs what the human takes as input, and vice-versa, leading to the fixed point equation x = human(computer(x))
, where x
is an Observable. The human and the computer are mutually observed. This is what we call “Functional Unidirectional Dataflow”, or “Reactive Dialogue”, and as an app developer you only need to specify the computer()
function.
import Cycle from '@cycle/core';
import {h, makeDOMDriver} from '@cycle/dom';
function main(responses) {
const requests = {
DOM: responses.DOM.select('.field').events('input')
.map(ev => ev.target.value)
.startWith('')
.map(name =>
h('div', [
h('label', 'Name:'),
h('input.field', {attributes: {type: 'text'}}),
h('h1', 'Hello ' + name)
])
)
};
return requests;
}
Cycle.run(main, {
DOM: makeDOMDriver('#app-container')
});
The computer function is main()
, with input responses
as a collection of Response Observables (event streams from ReactiveX), and outputs a collection of Request Observables. The human function is represented by the DOM Driver in the code above, because in the context of a web application, the DOM is a proxy to the user. The responsibility of main()
is to transform DOM Response Observables to DOM Request Observables, through a chain of RxJS operators. To learn more about this approach, the documentation will guide you through more details.
The building blocks in Cycle are Observables from RxJS, which simplify code related to events, asynchrony, and errors. Structuring the application with RxJS also separates concerns, because Observables decouple data production from data consumption. As a result, apps in Cycle have nothing comparable to imperative calls such as setState()
, forceUpdate()
, replaceProps()
, handleClick()
, etc. In the reactive pattern, no module has methods of the type foo.update()
, which normally leak responsibility of handling state living in foo
. You can write code with single responsibilities throughout.
Most frameworks claim to provide Separation of Concerns, but often they prescribe rigid containers where to place your code: Models, Views, Controllers, Components, Routes, Services, Dispatcher, Stores, Actions, Templates, etc. Cycle has none of that. Instead, pure functions over Observables and immutable data structures (such as from mori or Immutable.js) allow you to slice your program wherever you wish.
this
keyword. Cycle.js encourages you to create apps with functional practices. Without this
, you can write more reusable code and define logic without tightly coupling it to data. See it for yourself, this
cannot be found in Cycle.js TodoMVC.