For a cleanliness addict, the ideal front-end model should undoubtedly be:


> app = view(data)


There are two problems to be solved:


Where does ### data come from?


In React, hooks are tied to components or placed in redux. To the neatophiles, hooks are patches that break the elegance of the structure; Story is made outside the program depends on a piece of data, the program is no longer a fractal (https://baike.baidu.com/item/%E5%88%86%E5%BD%A2/85449). This is even more unacceptable, and the framework of the future should undoubtedly be fractal.


How to handle ### event?


In React, these event handlers are written to the UI and bound to callback functions to modify the data, which is more like a patch. These binding functions are scattered all over the place and difficult to organize and manage elegantly. And what about the one-way data flow? Data flows from above into the UI, and then modifies it in UI events, which is not “unidirectional” at least visually…


Let’s see how the cycle model looks:


### Stream produces data


In a cycle, events are also a special kind of data. They are data that is constantly spit out in a timeline. Take a Couter program for example:

const intent = (DOM: MainDOMSource) => xs.merge(  DOM.select('.dec').events('click').mapTo(-1),  DOM.select('.reset').events('click').mapTo(0),  DOM.select('.inc').events('click').mapTo(1),)Copy the code


As you can see, all events do not perform any operation, but map a data. This is an important change of thinking with FRP compared to traditional programs: ** There are no more “operations”, only data to data mapping **, the data generated by the stream is summarized to produce the final data for the view:


const model = (intent$: Stream<number>) => intent$  .fold((acc, i) => i ? acc + i : 0, 0)Copy the code


### Tree data generate view


This step is simple, pure rendering:


const view = (model$: Stream<number>) => model$.map(i =>  div('.f3', [    button('.dec'.The '-'),    button('.reset', i),    button('.inc'.'+')))Copy the code


The View layer is very pure, just pure rendering, without any event binding or anything extra.


Here’s the full code:


import xs, { Stream } from 'xstream'import { run } from '@cycle/run'import { div, button, makeDOMDriver, MainDOMSource } from '@cycle/dom'const intent = (DOM: MainDOMSource) => xs.merge(  DOM.select('.dec').events('click').mapTo(-1),  DOM.select('.reset').events('click').mapTo(0),  DOM.select('.inc').events('click').mapTo(1),)const model = (intent$: Stream<number>) => intent$  .fold((acc, i) => i ? acc + i : 0, 0)const view = (model$: Stream<number>) => model$.map(i =>  div('.f3', [    button('.dec'.The '-'),    button('.reset', i),    button('.inc'.'+'),  ]))run(  ({ DOM }: {DOM: MainDOMSource}) => ({ DOM: view(model(intent(DOM))) }),  { DOM: makeDOMDriver('#root')})Copy the code


** Cycle calls this mode MDI: Intent -> modle -> view**


# # to summarize


Cycle no longer has state and no event binding. Events map data, and data map views. This is the essence of functional programming: ** think of programs as data-to-data mappings **.