0

只是尝试一些愚蠢的东西并玩弄 Cycle.js。并遇到问题。基本上我只有一个按钮。当您单击它时,假设将位置导航到随机散列并显示它。几乎就像一个没有预定义路由的愚蠢路由器。IE。路线是动态的。这又不是什么实用的东西,我只是在弄乱一些东西并尝试学习 Cycle.js。但是在我单击“添加”按钮后,下面的代码会崩溃。但是位置已更新。如果我实际上只是导航到“#/asdf”,它会使用“Hash:#/asdf”显示正确的内容。不知道为什么流程因错误而崩溃:

render-dom.js:242 TypeError:无法读取未定义的属性“订阅”(...)

import Rx from 'rx';
import Cycle from '@cycle/core';
import { div, p, button, makeDOMDriver } from '@cycle/dom';
import { createHashHistory } from 'history';
import ranomdstring from 'randomstring';

const history = createHashHistory({ queryKey: false });

function CreateButton({ DOM }) {
  const create$ = DOM.select('.create-button').events('click')
    .map(() => {
      return ranomdstring.generate(10);
    }).startWith(null);

  const vtree$ = create$.map(rs => rs ?
    history.push(`/${rs}`) :
    button('.create-button .btn .btn-default', 'Add')
  );

  return { DOM: vtree$ };
}

function main(sources) {
  const hash = location.hash;
  const DOM = sources.DOM;

  const vtree$ = hash ?
    Rx.Observable.of(
      div([
        p(`Hash: ${hash}`)
      ])
    ) :
    CreateButton({ DOM }).DOM;

  return {
    DOM: vtree$
  };
}

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

感谢您的帮助

4

2 回答 2

5

我会进一步建议使用@cycle/history 来改变你的路线(只显示相关部分)

import {makeHistoryDriver} from '@cycle/history'
import {createHashHistory} from 'history'

function main(sources) {
  ...
  return {history: Rx.Observable.just('/some/route') } // a stream of urls
}

const history = createHashHistory({ queryKey: false })
Cycle.run(main, {
  DOM: makeDOMDriver('#main-container'),
  history: makeHistoryDriver(history),
})
于 2016-03-28T23:04:12.360 回答
2

在您的功能CreateButton上,您将点击映射到history.push()而不是将其映射到导致错误的 vtree :

function CreateButton({ DOM }) {
  ...
  const vtree$ = create$.map(rs => rs
    ? history.push(`/${rs}`) // <-- not a vtree
    : button('.create-button .btn .btn-default', 'Add')
  );
  ...
}

相反,您可以使用 do 运算符来执行 hashchange:

function CreateButton({ DOM }) {
  const create$ = 
    ...
    .do(history.push(`/${rs}`)); // <-- here

  const vtree$ = Observable.of(
    button('.create-button .btn .btn-default', 'Add')
  );
  ...
}

然而在函数式编程中你不应该对你的应用逻辑产生副作用,每个函数都必须保持纯净。相反,所有副作用都应由驱动程序处理。要了解更多信息,请查看Cycle 文档中的驱动程序部分

在消息的末尾看到一个工作的驱动程序跳转。


此外,在您的main功能上,您没有使用流来呈现您的 vtree。它不会对 locationHash 更改做出反应,因为vtree$ = hash ? ... : ...仅在应用程序引导时评估一次(当评估主函数并将每个流“连接”在一起时)。

一个改进是声明你main的 vtree$ 如下,同时保持相同的逻辑:

const vtree$ = hash$.map((hash) => hash ? ... : ...)

这是一个带有小型 locationHash 驱动程序的完整解决方案:

import Rx from 'rx';
import Cycle from '@cycle/core';
import { div, p, button, makeDOMDriver } from '@cycle/dom';
import { createHashHistory } from 'history';
import randomstring from 'randomstring';


function makeLocationHashDriver (params) {
  const history = createHashHistory(params);

  return (routeChange$) => {
    routeChange$
      .filter(hash => {
        const currentHash = location.hash.replace(/^#?\//g, '')
        return hash && hash !== currentHash
      })
      .subscribe(hash => history.push(`/${hash}`));

    return Rx.Observable.fromEvent(window, 'hashchange')
      .startWith({})
      .map(_ => location.hash);
  }
}

function CreateButton({ DOM }) {
  const create$ = DOM.select('.create-button').events('click')
    .map(() => randomstring.generate(10))
    .startWith(null);

  const vtree$ = Rx.Observable.of(
    button('.create-button .btn .btn-default', 'Add')
  );

  return { DOM: vtree$, routeChange$: create$ };
}

function main({ DOM, hash }) {
  const button = CreateButton({ DOM })
  const vtree$ = hash.map(hash => hash
    ? Rx.Observable.of(
        div([
          p(`Hash: ${hash}`)
        ])
      )
    : button.DOM
  )

  return {
    DOM: vtree$,
    hash: button.routeChange$
  };
}

Cycle.run(main, {
  DOM: makeDOMDriver('#main-container'),
  hash: makeLocationHashDriver({ queryKey: false })
});

PS:你的函数名有错别字randomstring,我在我的例子中修正了它。

于 2016-03-28T19:19:07.537 回答