[Cycle.js] Read effects from the DOM: click events

So far we only had effects that write something to the external world, we are not yet reading anything from the external world into our app. This lesson shows how we can change the DOM Driver to return a "DOM Source" representing read effects, such as click events. We will leverage that to create an interactive application.

 

复制代码
// Logic (functional)
function main() {
  return {
    DOM: Rx.Observable.timer(0, 1000)
      .map(i => `Seconds elapsed ${i}`),
    Log: Rx.Observable.timer(0, 2000).map(i => 2*i),
  };
}

// Effects (imperative)
function DOMEffect(text$) {
  text$.subscribe(text => {
    const container = document.querySelector('#app');
    container.textContent = text;
  });
}

function consoleLogEffect(msg$) {
  msg$.subscribe(msg => console.log(msg));
}

const effects = {
    DOM: DOMEffect,
    Log: consoleLogEffect
}

function run(mainFn, effects){
  const sinks = mainFn();
  Object.keys(effects)
    .forEach( (effectKey)=>{
    effects[effectKey](sinks[effectKey]);
  })
}

run(main, effects);
复制代码

 

Source: stands for input, read effect

sink: stands for output, write effect

 

So main() function need to take a param 'DOMSource' and effects function need return value:

复制代码
function main(DOMSource) {
   ...   
}

function DOMDriver() {
  ...
  const DOMSource = Rx.Observable.fromEvent(document, 'clicik');
  return DOMSource;  
}

function run(mainFn, drivers) {
   const sinks = mainFn(DOMSource);
   const DOMSource = drivers['DOM'](sinks['DOM'])
   ....
}
复制代码

The problem in the code above is that:

  the main function need param 'DOMSource' which is returned by the driver DOMDriver. But for create DOMSource in run() function, we need pass DOMSource to the main() function. So 'DOMSource' is actually used before it created.

 

I can simply the problem as:

a = f(b); // we need b to create a

b = g(a) // we need a to create b

So there is a cycle going on between main() function and driver() function.

 

The solution to sovle this problem is :

 A is an observable and also B is an observable. If we actually instead of using B, we could use something like B proxy here. Because B proxy is now available for f() as an argument.

Then that helps us to make A, and then given A we can make B. Then now that we have B, we can feed back all of the events that happen on B into B proxy. So that's what we're going to try to achieve.

bProxy = ...

a = f(bProxy)

b = g(a)

bProxy.imitat(b)

 

So the code looks like:

复制代码
// Logic (functional)
function main(DOMSource) {
  const click$ = DOMSource;
  return {
    DOM: click$
      .startWith(null)
      .flatMapLatest(() => 
        Rx.Observable.timer(0, 1000)
         .map(i => `Seconds elapsed ${i}`)           
      ),
    Log: Rx.Observable.timer(0, 2000).map(i => 2*i),
  };
}

// source: input (read) effects
// sink: output (write) effects

// Effects (imperative)
function DOMDriver(text$) {
  text$.subscribe(text => {
    const container = document.querySelector('#app');
    container.textContent = text;
  });
  const DOMSource = Rx.Observable.fromEvent(document, 'click');
  return DOMSource;
}

function consoleLogDriver(msg$) {
  msg$.subscribe(msg => console.log(msg));
}

// bProxy = ...
// a = f(bProxy)
// b = g(a)
// bProxy.imitate(b)

function run(mainFn, drivers) {
  const proxyDOMSource = new Rx.Subject();
  const sinks = mainFn(proxyDOMSource);
  const DOMSource = drivers.DOM(sinks.DOM);
  DOMSource.subscribe(click => proxyDOMSource.onNext(click));
//   Object.keys(drivers).forEach(key => {
//     drivers[key](sinks[key]);
//   });
}

const drivers = {
  DOM: DOMDriver,
  Log: consoleLogDriver,
}

run(main, drivers);

  
复制代码

 

posted @   Zhentiw  阅读(216)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示