【问题标题】:RxJs flatMap to Rx.DOM.getJson not firingRxJs flatMap 到 Rx.DOM.getJson 没有触发
【发布时间】:2016-09-11 16:58:37
【问题描述】:

有时我很难让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 正在取消请求,如下所示。

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

编辑 我刚刚注意到删除 react 允许 Rx.DOM 调用成功。

【问题讨论】:

    标签: rxjs


    【解决方案1】:

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

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

    您的第一个问题是每次渲染都会触发“LoadPosts”操作,而无需单击按钮,这会导致无限渲染循环。渲染->LoadPosts->渲染->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 不再发出值。

    【讨论】:

    • 感谢@omerts 的详细回复。您是否有任何关于在 .catch() 中记录错误的良好模式的详细信息?
    • 我们也在寻找最好的模式。但是现在,在 catch() 中,你可以记录并返回 Observable.empty(),或者记录并返回一个 observable,它会发出一个错误对象,并在 UI 中显示一些错误。
    猜你喜欢
    • 1970-01-01
    • 2020-03-05
    • 1970-01-01
    • 1970-01-01
    • 2018-12-19
    • 2019-08-24
    • 1970-01-01
    • 1970-01-01
    • 2017-09-10
    相关资源
    最近更新 更多