首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >cyclejs是否应该像Elm/Redux那样建模操作?

cyclejs是否应该像Elm/Redux那样建模操作?
EN

Stack Overflow用户
提问于 2018-02-26 15:13:11
回答 1查看 70关注 0票数 0

我正在尝试cyclejs,我正在尝试找出处理许多来源/意图的惯用方式应该是什么。我在下面的TypeScript中有一个简单的cyclejs程序,对最相关的部分进行了注释。

您是否应该像在Elm或Redux中那样将源/意图建模为谨慎的事件,或者您是否应该在流操作方面做一些更聪明的事情?当应用程序很大时,我很难理解如何避免这种事件模式。

如果这是正确的方式,它不会最终成为增加了流管理复杂性的Elm的JS版本吗?

代码语言:javascript
复制
import { div, DOMSource, h1, makeDOMDriver, VNode, input } from '@cycle/dom';
import { run } from '@cycle/xstream-run';
import xs, { Stream } from 'xstream';

import SearchBox, { SearchBoxProps } from './SearchBox';


export interface Sources {
    DOM: DOMSource;
}

export interface Sinks {
    DOM: Stream<VNode>
}

interface Model {
    search: string
    searchPending: {
        [s: string]: boolean
    }
}

interface SearchForUser {
    type: 'SearchForUser'
}

interface SearchBoxUpdated {
    type: 'SearchBoxUpdated',
    value: string
}


type Actions = SearchForUser | SearchBoxUpdated;

/**
 * Should I be mapping these into discreet events like this?
 */
function intent(domSource: DOMSource): Stream<Actions> {
    return xs.merge(
        domSource.select('.search-box')
            .events('input')
            .map((event: Event) => ({
                type: 'SearchBoxUpdated',
                value: ((event.target as any).value as string)
            } as SearchBoxUpdated)),

        domSource.select('.search-box')
            .events('keypress')
            .map(event => event.keyCode === 13)
            .filter(result => result === true)
            .map(e => ({ type: 'SearchForUser' } as SearchForUser))
    )
}

function model(action$: Stream<Actions>): Stream<Model> {
    const initialModel: Model = {
        search: '',
        searchPending: {}
    };

    /*
     * Should I be attempting to handle events like this?
     */
    return action$.fold((model, action) => {
        switch (action.type) {
            case 'SearchForUser':
                return model;

            case 'SearchBoxUpdated':
                return Object.assign({}, model, { search: action.value })
        }
    }, initialModel)
}



function view(model$: Stream<Model>): Stream<VNode> {
    return model$.map(model => {
        return div([
            h1('Github user search'),
            input('.search-box', { value: model.search })
        ])
    })
}

function main(sources: Sources): Sinks {

    const action$ = intent(sources.DOM);
    const state$ = model(action$);

    return {
        DOM: view(state$)
    };
}

run(main, {
    DOM: makeDOMDriver('#main-container')
});
EN

回答 1

Stack Overflow用户

发布于 2018-02-27 17:32:35

在我看来,您不应该像您那样多路复用意图流(将所有意图合并到单个流中)。

相反,您可以尝试在intent函数中返回多个流。

类似于:

代码语言:javascript
复制
function intent(domSource: DOMSource): SearchBoxIntents {
  const input = domSource.select("...");
  const updateSearchBox$: Stream<string> = input
    .events("input")
    .map(/*...*/)

  const searchForUser$: Stream<boolean> = input
    .events("keypress")
    .filter(isEnterKey)
    .mapTo(true)

  return { updateSearchBox$, searchForUser$ };
}

然后,您可以将这些操作映射到model函数中的缩减程序,合并这些缩减程序,最后对它们执行fold操作

代码语言:javascript
复制
function model({ updateSearchBox$, searchForUser$ }: SearchBoxIntents): Stream<Model> {
  const updateSearchBoxReducer$ = updateSearchBox$
    .map((value: string) => model => ({ ...model, search: value }))

  // v for the moment this stream doesn't update the model, so you can ignore it
  const searchForUserReducer$ = searchForUser$
    .mapTo(model => model);

  return xs.merge(updateSearchBoxReducer$, searchForUserReducer$)
    .fold((model, reducer) => reducer(model), initialModel);
}

此解决方案具有多项优势:

你可以输入你的函数的参数,并检查是否传递了正确的流;如果动作的数量increases;

  • you不需要动作identifiers.

,你就不需要很大的

  • switch

在我看来,当两个组件之间存在父/子关系时,多路复用/多路分解流是很好的。这样,父级只能使用它需要的events (这更像是一种直觉,而不是一般规则,它需要更多的思考:)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48983189

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档