2016-10-14 14 views
5

私にはいくつかの選択肢がありますが、どちらも少し遅れているようですが、もっと良い選択肢があるはずです。フォームを作成したり、動的に作成したり(アプリケーション内からフォームに行を追加するなど)、フォームを作成したり、異なる入力の値に試薬/フレーム/反応に適切なアクセスを持たせたいだけです。 ...彼らは両方のすべての:on-change後に機能を実行するため、これらのいずれかが、しかし最善の選択肢である場合にClojure Re-Frameで入力要素を処理するにはどうすればよいですか?

わからない

オプション#1 - グローバルアトム

[:input {:value  @new-job-form 
     :on-change #(dispatch [:new-job-form (-> % .-target .-value)])}] 

(reg-event-db 
:new-job-form 
(fn [db [_ v]] 
    (assoc db :new-job-form v))) 

に更新:on-changeオプション#2 - 一部のローカルステートを更新し、グローバルアトムにのみディスパッチする:on-blur

(defn text-input 
    "adapted from: 
    https://yogthos.net/posts/2016-09-25-ReagentComponents.html 

    The big idea is this holds local state, and pushes it to the global 
    state only when necessary" 
    [{:keys [sub-path disp]}] 
    (r/with-let [value (r/atom nil) 
       focused? (r/atom false)] 
    [:div 
    [:input 
     {:type  :text 
     :on-focus #(do (reset! value @(subscribe sub-path)) 
         (reset! focused? true)) 
     :on-blur #(do (dispatch (conj disp @value)) 
         (reset! focused? false)) 
     :value  (if @focused? @value @(subscribe sub-path)) 
     :on-change #(reset! value (-> % .-target .-value))}]])) 

第二の選択肢がやや少ないラグですが、ちょうど生のテキスト入力よりも多くのラグ...

EDIT:

オプション#3 - 完全にするために、わずかに異なる味が再から適応-frameのTODOMVC

(defn text-input 
    "adapted from re-frame's TODOMVC: 
     https://github.com/Day8/re-frame/blob/master/examples/todomvc/src/todomvc/views.cljs 

    note: this is one-way bound to the global atom, it doesn't subscribe to it" 
    [{:keys [on-save on-stop props]}] 
    (let [inner (r/atom "")] 
    (fn [] [:input (merge props 
          {:type  "text" 
          :value  @inner 
          :on-blur  (on-save @inner) 
          :on-change #(reset! inner (-> % .-target .-value)) 
          :on-key-down #(case (.-which %) 
              13 (on-save @inner) ; enter 
              27 (on-stop) ; esc 
              nil)})]))) 

[text-input {:on-save #(dispatch [:new-job-form {:path [:a] 
                 :v %}]) 
        :on-stop #(js/console.log "stopp") 
        :props {:placeholder "url"}}] 
+0

ラグはどういう意味ですか?あなたは実際にパフォーマンスの目に見える低下を経験していますか?あなたが記述した2つの方法のいずれかを使用してかなり多くのことを達成しましたが、パフォーマンスの問題は一度もありませんでした。 –

+0

@KubaBireckiはい、テキストボックスが自分の入力に追いつくのに苦労するので、パフォーマンスが目に見えて低下します。私は高速のコンピュータを持っていますが、遅くなければならない他の明白な理由はありません。 –

+0

私はあなたの要件が正確かどうかはっきりしていませんが、私はtodomvcの再構成とそれがどのようにtodosを追加するのかを見て始めましょう。 -frame/tree/master/examples/todomvc –

答えて

0

再フレーム、および低レベルでreagent + Reactは、変更するコンポーネントを再レンダリングを制限しよう。あなたのケースでは、変更された唯一のものであったテキストフィールドに加えて、別のコンポーネント(またはUI全体)が再レンダリングされた場合、遅れが生じることがあります。

あなたの「オプション1」に構築例:

(defn busy-wait [ms] 
    (let [start (.getTime (js/Date.))] 
    (while (< (.getTime (js/Date.)) (+ start ms))))) 

(defn slow-component [] 
    (busy-wait 2000) 
    (.log js/console "Ouch!") 
    [:h2 "I was busy"]) 

(defn main-panel [] 
    (let [new-job-form (re-frame/subscribe [:new-job-form]) 
    (fn [] 
     [:div.container-fluid 
     (slow-component) 
     [:input  {:value @new-job-form 
     :on-change #(dispatch [:new-job-form (-> % .-target .-value)])}] 
;; etc 

これはslow-component再レンダリングするたびにテキストを入力し、slow-componentをレンダリングするために、少なくとも2000ミリ秒かかるので、本当にラグですにつながります。上記の場合

、簡単な解決策は、すなわち、ベクターへの呼び出しを変更、再フレーム関数としてslow-componentを提供することである。

[:div.container-fluid 
    [slow-component] 

このことを確認するために再フレーム可能slow-componentは、データが変更されていないため、再レンダリングする必要はありません。良い習慣は、サブスクリプションへの結合時にForm-2 componentsを使用することもある

[:div.container-fluid 
    (slow-component) 

:私たちは元の例では機能自分自身を呼び出すときに私たちは、この推論をスキップします。

関連する問題