我可能正在尝试一些愚蠢的事情,但是我有一个足够大的非洋葱化 Cycle.js 应用程序,并且我正在尝试了解onionify 的工作原理,所以我想将一个洋葱化组件嵌入到我原来的非洋葱应用程序中。
所以我有一个简单的 onion-ready 组件,增量/减量示例,还有一个简单的非洋葱循环应用程序,“Hello Last Name”</a> 示例——我如何将两者结合在一起,这样我就有了在同一个网页中一个接一个的增量组件和Hello组件?
Counter.ts
, 洋葱准备组件
import xs from 'xstream';
import run from '@cycle/run';
import { div, button, p, makeDOMDriver } from '@cycle/dom';
export default function Counter(sources) {
const action$ = xs.merge(
sources.DOM.select('.decrement').events('click').map(ev => -1),
sources.DOM.select('.increment').events('click').map(ev => +1)
);
const state$ = sources.onion.state$;
const vdom$ = state$.map(state =>
div([
button('.decrement', 'Decrement'),
button('.increment', 'Increment'),
p('Counter: ' + state.count)
])
);
const initReducer$ = xs.of(function initReducer() {
return { count: 0 };
});
const updateReducer$ = action$.map(num => function updateReducer(prevState) {
return { count: prevState.count + num };
});
const reducer$ = xs.merge(initReducer$, updateReducer$);
return {
DOM: vdom$,
onion: reducer$,
};
}
index.ts
, 非洋葱主应用
import xs, { Stream } from 'xstream';
import { run } from '@cycle/run';
import { div, input, h2, button, p, makeDOMDriver, VNode, DOMSource } from '@cycle/dom';
import Counter from "./Counter";
import onionify from 'cycle-onionify';
const counts = onionify(Counter);
interface Sources {
DOM: DOMSource;
}
interface Sinks {
DOM: Stream<VNode>;
}
function main(sources: Sources): Sinks {
const firstName$ = sources.DOM
.select('.first')
.events('input')
.map(ev => (ev.target as HTMLInputElement).value)
.startWith('');
const lastName$ = sources.DOM
.select('.last')
.events('input')
.map(ev => (ev.target as HTMLInputElement).value)
.map(ln => ln.toUpperCase())
.startWith('');
const rawFullName$ = xs.combine(firstName$, lastName$)
.remember();
const validName$ = rawFullName$
.filter(([fn, ln]) => fn.length > 0 && ln.length >= 3)
.map(([fn, ln]) => `${ln.toUpperCase()}, ${fn}`);
const invalidName$ = rawFullName$
.filter(([fn, ln]) => fn.length === 0 || ln.length < 3)
.mapTo('');
const name$ = xs.merge(validName$, invalidName$);
const vdom$ = name$.map(name =>
div([
p([
'First name',
input('.first', { attrs: { type: 'text' } }),
]),
p([
'Last name',
input('.last', { attrs: { type: 'text' } }),
]),
h2('Hello ' + name),
]),
);
return {
DOM: vdom$,
};
}
run(main, {
DOM: makeDOMDriver('#main-container'),
});
尝试
如果我替换run(main, ...)
为run(counts, ...)
,就像 cycle-onionify 文档建议的完全洋葱化的应用程序一样,我只会看到预期的计数器。
但是counts
,由于 , 的输出onionify(Counter)
是一个函数,所以我认为我不能在我的 main() 中“实例化”它。
同样,我认为我不能通过Counter()
在 main 内部调用来创建计数器组件,因为该函数需要sources.onion
输入,而且我不确定如何创建.onion
具有 type 的字段StateSource
。
问题
我如何Counter
在我的 non-onionified 中使用这个 onion-ready 组件main
?
完整示例
完整示例可在https://gist.github.com/fasiha/939ddc22d5af32bd5a00f7d9946ceb39获得——克隆它,npm install
以获取必要的包,然后make
(运行tsc
并browserify
转换 TypeScript→JavaScript→browserified JS)。