cyclejs는 observable을 logic, subscribe를 effect로 각각 분리하고 서로 순환하는 구조인 full reactive framework 이다.
예를 들면 1초(1000ms)마다 스트림을 발산하는 text$는 매번 fold(reduce)하여 1씩 증가하고 "Second elapsed xx"로 map하는
이를 subscribe 하여 #app element의 텍스트로 넣는 것을
이를 각각 함수로 구분하여
같은 logic에 대해 DOM 렌더링과 log를 분리하려면 logDriver를 아래와 같이 추가하여
subscribe한 객체의 observable만 있으면 DOM이건 console이건 canvas건 websocket이건 어느쪽이든 effect를 만들어 낼 수 있다.
만일 위의 예에서 logDriver와 domDriver가 다른 logic을 수행한다면 어떨까?
이걸 일반화해보자. n개의 driver들이 있고 우리는 이걸 한번에 묶어서 실행하는 runner를 만들고 싶다.
여기서 좀 더 runner를 유연하게 해보자.
만일 domDriver 에서 하드코드로 "#app"인 element를 지정하는게 아니라 인자로 받게 하면 어떨까?
그렇다면 function을 반환하는 함수를 "실행"해야한다.
그런 driver를 makeDomDriver라고 하고 구현해보자.
logDriver도 같은 방식으로 정리하고 모아보면
이것이 cycle.js의 근간을 이루고 있는 아이디어이며.
요컨데 logic으로 effect를 만드는 함수를 driver라고 한다.
예를 들면 1초(1000ms)마다 스트림을 발산하는 text$는 매번 fold(reduce)하여 1씩 증가하고 "Second elapsed xx"로 map하는
text$=xs.periodic(1000)를 logic.
.fold(prev=>prev+1,0)
.map(i=>`Second elapsed ${i}`)
이를 subscribe 하여 #app element의 텍스트로 넣는 것을
text$.subscrbie({를 effect로 볼 수 있다.
next: str => document.querySelector('#app').textContent = str
})
이를 각각 함수로 구분하여
const sink = ()=> xs.periodic(1000)이와 같이 재정의 할 수 있다.
.fold(prev=>prev+1,0)
.map(i=>`Second elapsed ${i}`);
const domDriver = text$ => text$.subscribe({
next: str => document.querySelector('#app').textContent = str
});
domDriver(sink);
같은 logic에 대해 DOM 렌더링과 log를 분리하려면 logDriver를 아래와 같이 추가하여
const logDriver = msg => console.log(msg);하여도 마찬가지.
logDriver(sink);
subscribe한 객체의 observable만 있으면 DOM이건 console이건 canvas건 websocket이건 어느쪽이든 effect를 만들어 낼 수 있다.
만일 위의 예에서 logDriver와 domDriver가 다른 logic을 수행한다면 어떨까?
const sinks = ()=> ({이와 같이 sinks로 만들고 각각의 driver들이 sinks의 키를 가져오면 될 것이다.
DOM: xs.periodic(1000)
.fold(prev=>prev+1,0)
.map(i=>`Second elapsed ${i}`),
log: xs.periodic(1000)
.fold(prev=>prev+1,0)
})
domDriver(sinks.DOM);
logDriver(sinks.log);
이걸 일반화해보자. n개의 driver들이 있고 우리는 이걸 한번에 묶어서 실행하는 runner를 만들고 싶다.
const runner = (sinks, drivers)=> {이와 같이 정리할 수 있다.
for (idx in drivers) {
drivers[idx] && drivers[idx](sinks[idx]);
}
}
runner(sinks, {
DOM: domDriver,
log: logDriver
});
여기서 좀 더 runner를 유연하게 해보자.
만일 domDriver 에서 하드코드로 "#app"인 element를 지정하는게 아니라 인자로 받게 하면 어떨까?
runner(sinks, {가령 이런 식으로 말이다.
DOM: domDriver("#app"),
log: logDriver
});
그렇다면 function을 반환하는 함수를 "실행"해야한다.
그런 driver를 makeDomDriver라고 하고 구현해보자.
const makeDomDriver = target =>그러면, 인자를 받아도 여전히 text$를 인자로 하는 무기명 함수를 지정한다.
text$ => text$.subscribe({
next: str => document.querySelector(target).textContent = str
});
logDriver도 같은 방식으로 정리하고 모아보면
const makeLogDriver = ()=>이와 같은 형태로 만들 수 있다.
msg => console.log(msg);
runner(sinks, {
DOM: makeDomDriver("#app"),
log: makeLogDriver()
});
이것이 cycle.js의 근간을 이루고 있는 아이디어이며.
요컨데 logic으로 effect를 만드는 함수를 driver라고 한다.
댓글
댓글 쓰기