RxJs flatMap到Rx.DOM.getJson没有触发

时间:2016-05-15 23:42:40

标签: rxjs

我很难让某些时间flatMapRx.DOM.getJson()合作,并且无法弄清楚我做错了什么。

HTML

<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.1.0/rx.all.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs-dom/7.0.3/rx.dom.js"></script>
<script src="https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-xta1/t39.3284-6/12624096_747368668729465_1053913233_n.js"></script>
<script src="https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-xaf1/t39.3284-6/12624065_1518596455100766_427485197_n.js"></script>
  <title>JS Bin</title>
</head>
<body>
  <button id='fetch'>Fetch</button>
  <div id="content"></div>
</body>
</html>

的javascript

// Actions
const Actions = {
  LoadPosts: 'LoadPosts'
};

// Disptacher
const Dispatcher = new Rx.Subject();

function send(action) {
  Dispatcher.onNext({action: action});
}

// Stores
const url = 'http://jsonplaceholder.typicode.com/posts';

const FetchedPosts$ = Dispatcher
  .filter(x => Actions.LoadPosts === x.action)
  .do(x => console.log(x))
  .flatMap(() => {
    console.log('flat');
    return Rx.DOM.getJSON(url);
  })
  .do(x => console.log('after', x));

// Views
const fetchButton = document.getElementById('fetch');
const Fetch$ = Rx.Observable.fromEvent(fetchButton, 'click')
  .do(x => send(Actions.LoadPosts));

const PostsView$ 
  = FetchedPosts$.map(posts => posts.map(post => <li>{post.title}</li>));

const RootView$ = Rx.Observable.merge(Fetch$, PostsView$);

RootView$.subscribe(
  content => ReactDOM.render(
    <ul>{content}</ul>, 
    document.getElementById('content')
  )
);

输出

[object Object] {
  action: "LoadPosts"
}
"flat"
"Script error. (line 0)"

所以输出显示我进入平面地图,如果我拿出Rx.DOM.getJSON(url)并订阅它,那么我可以写出返回的值。但是,在flatMap中没有任何内容返回,我在网络选项卡中看到一个错误,显示Rx正在取消请求,如下所示。

enter image description here

这是一个JsBin:http://jsbin.com/geruzo/edit?js,console,output

修改 我刚刚注意到,remove react允许Rx.DOM调用成功。

1 个答案:

答案 0 :(得分:1)

好的,我将通过参考您的jsbin代码来回答,这与发布的代码不同,但我更容易检查。

首先,您可以在此处找到固定版本的代码: http://jsbin.com/yugener/edit?html,js,output

您的第一个问题是每次渲染都会触发“LoadPosts”操作,而不必单击按钮,这会导致无限的渲染循环。 Render-&GT; LoadPosts-&GT; Render-&GT; LoasPosts ...

// The send will just be executed when the component is rendered
<button click={send(Actions.LoadPosts)}>fetch</button>

它应该是(也是onClick,而不是点击):

<button onClick={() => send(Actions.LoadPosts)}>Fetch</button>

由于存在渲染循环,并且“LoadPosts”操作一直处于触发状态,因此在上一个请求完成之前再次调用Rx.DOM.getJSON,因此它将取消之前的请求。你不会抛出一个错误(请求中止等),并抓住它:

.flatMap(() => Rx.DOM.getJSON('http://jsonplaceholder.typicode.com/posts'))
.catch(error => console.log('error', error))

在RXJS中,catch操作符期望您返回一个observable,并且由于您没有,返回undefined,这反过来又引发了以下错误:

Uncaught TypeError: Cannot read property 'subscribe' of undefined

作为旁注,在您的情况下,不应使用flatMap,您应该使用switchMap(别名flatMapLatest),因为每次触发“LoadPosts”操作时,您都希望忽略所有先前的请求,并仅从最后一个获取数据请求。 有关两者之间差异的更多信息:flatMap vs switchMap。如果您可能希望通过设计中止先前的请求,flatMap也会避免出现“中止”错误,因为之前的observable不再发出值。