【问题标题】:Re-run subscription on input change在输入更改时重新运行订阅
【发布时间】:2017-10-23 18:11:24
【问题描述】:

我正在尝试创建一个 re-frame 订阅,它从 REST API 而不是本地数据库读取数据并将这些数据保存到数据库中。 REST 调用取决于重新框架数据库中的其他值(想想 API-Key),虽然这些数据在浏览应用程序时可用,但在重新加载时不可用。我正在关注本教程:https://github.com/Day8/re-frame/blob/master/docs/Subscribing-To-External-Data.md#some-code

我的订阅看起来像这样(为了便于阅读,去掉了):

(rf/reg-sub-raw :organisation-users (fn [db [_ api-token organisation]] (when (not (nil? api-token))] (ajax/GET (str "/some-url/to/get/users/for/organisation") {:params {:api-token api-token} :handler #(rf/dispatch [:organisation-users-change %]) :format (ajax/json-request-format) :response-format (ajax/json-response-format {:keywords? true})})) (ratom/make-reaction (fn [] (:organisation-users @db)))))

订阅通过 API-Key 并从服务器请求组织用户。如果数据库中的organisation-users 发生更改,它会返回一个更新订阅者的响应,这会在其余调用成功后立即发生。

在我的组件中,我订阅了订阅:

(defn organisation-page [] (let [api-token (rf/subscribe [:api-token]) organisation-users (rf/subscribe [:organisation-users @api-token])] (fn [] [:div {:class "columns"} ))); stripped

如果我重新加载页面并在初始化(初始化 api-token)之后让 organisation-page 呈现,则此代码有效。 organisation-page 组件在加载后立即渲染时不起作用,因为 api-token 尚不可用并且它不会再次执行 rest 调用。

我也尝试将整个订阅包装到反应中,但这会导致无限循环,因为每次数据库中 organisation-users 更改时都会执行整个反应,这会再次执行其余调用,从而再次触发反应并以此类推。

我将如何以“重新构建方式”解决这个问题?我的一个想法是仅在 organisation-users 尚未填充到数据库中时才执行其余调用。这可能有效,但我担心如果用户稍后导航到该页面并查看旧数据,或者如果调用不成功并且用户无法通过再次导航到该页面来启动新尝试,我会遇到问题。

【问题讨论】:

    标签: clojurescript reagent re-frame


    【解决方案1】:

    我将获取用户转移到一个事件中。

    为了测试它,我伪造了响应,但请注意,您可以使用 http-fx 很好地将 ajax 调用嵌入到事件中(请参阅注释掉的事件)。

    请注意,由于subscription caching/deduplication,您可以立即取消订阅。

    (ns simple.core
      (:require [reagent.core :as r]
                [re-frame.core :refer [reg-sub
                                       reg-event-fx
                                       reg-sub-raw
                                       dispatch
                                       subscribe
                                       dispatch-sync]]))
    
    (reg-sub
      :api-token
      (fn [db _]
        (get db :api-token)))
    
    (reg-event-fx
      :api-token
      (fn [{:keys [:db]} [_ api-token]]
        {:db (assoc db :api-token api-token)}))
    
    (reg-event-fx
      :good-organisation-users
      (fn [{:keys [:db]} [_ response]]
        {:db (assoc db :organisation-users response)}))
    
    (def responses {"123" [{:name "Foo"}]
                    "456" [{:name "Foo"} {:name "Bar"}]})
    
    (reg-event-fx
      :fetch-organisation-users
      (fn [{:keys [:db]} [_ api-token]]
        (.log js/console "fetching users with api-token" api-token)
        {:dispatch [:good-organisation-users (get responses api-token)]}))
    
    (defn fetch-users! []
      (let [api-token @(subscribe [:api-token])]
        (when api-token
          (dispatch [:fetch-organisation-users api-token]))))
    
    (reg-sub-raw
      :organisation-users
      (fn [app-db [_]]
        (let [fetcher (r/track! fetch-users!)]
          (reagent.ratom/make-reaction
            (fn []
              (get @app-db :organisation-users))
            :on-dispose #(r/dispose! fetcher)))))
    
    (defn organisation-page
      []
      (let [organisation-users @(subscribe [:organisation-users])]
        [:div 
         (when organisation-users
           [:ul
            (for [user organisation-users]
              ^{:key (:name user)}
              [:li (:name user)])])]))
    
    (defn ^:export run
      []
      (dispatch [:api-token "123"])
      (js/setTimeout #(dispatch [:api-token "456"]) 3000)
      (r/render [organisation-page]
                js/klipse-container))
    
    
    (run)
    

    为了证明它有效,您可以在http://app.klipse.tech/?container&cljs_in.gist=borkdude/f228103b2eaa04b92c5b532485fbd2ef实时查看它

    【讨论】:

    • 使用您的代码,如果我在 api-token 可用后渲染 organisation-page,它确实有效。如果api-token还不可用,它确实会等待令牌并在后面执行http请求。我可以看到:good-organisation-users 事件触发并接收到正确的数据。但是organisation-page 不会自行重新渲染。有什么想法吗?
    • 只是一个健全的检查:你使用哪个 Re-frame 版本?
    • 那就是[re-frame "0.9.4"]
    • 我发现了一些错字并查看了我的答案。我还添加了一个指向 Klipse 的链接,在那里你可以看到它有效:app.klipse.tech/?container&cljs_in.gist=borkdude/…
    • 我可以看到它在 klipse 上运行,谢谢!我会尝试弄清楚为什么它在我的代码中不起作用!
    猜你喜欢
    • 1970-01-01
    • 2012-12-20
    • 1970-01-01
    • 2021-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-05
    相关资源
    最近更新 更多