首页 文章

渲染后的Om回调(在更改应用程序状态后聚焦元素)

提问于
浏览
4

我有一个文本输入元素,它使用组件状态和应用程序状态 .

React: More About Refs中显示的示例中,目标是在重新渲染后在元素上调用 focus . 这是关键部分,在React中使用JS完成 .

clearAndFocusInput: function() {
  // Clear the input
  this.setState({userInput: ''}, function() {
    // This code executes after the component is re-rendered
    this.refs.theInput.getDOMNode().focus();   // Boom! Focused!
  });
},

我想用Om做类似的事情 . 我也没注意到

  • Om的 set-state! (用于更改组件状态;请参阅docssource),也不

  • Om的 update! (用于更改应用程序状态;请参阅docssource

提供了指定回调的方法 . 因此,我正在寻找其他方法,以便在重新渲染之后导致某些事情发生 .

这是我的例子:

(defn input-component
  [{:keys [app-state-key class-name]}]
  (fn [data owner]
    (reify
      om/IInitState
      (init-state
        [this]
        {:text (data app-state-key)})

      om/IRenderState
      (render-state
        [this state]
          (let [handle-change (handle-change-fn data app-state-key)]
            (dom/input
              #js {:ref (name app-state-key)
                   :type "text"
                   :className class-name
                   :value (:text state)
                   :onChange #(handle-change % owner state)}))))))

(defn handle-change-fn
  [app-state app-state-key]
  (fn [e owner state]
    (let [element (.-target e)
          value (.-value element)]
      (om/set-state! owner :text value)
      (if-let [value' (parse-int value)]
        (om/update! app-state app-state-key value')))))

(注意: parse-int ,未显示,"cleans up"组件状态,以便它适合应用程序状态 . )

更改文本输入的组件状态不会导致它失去焦点,但会改变应用程序状态 .

我已经尝试过使用core.async通道,但这似乎没有用,因为我只希望在重新渲染完成后进行回调 .

我也试过用 IDidUpdate ,像这样:

(defn input-component
  [{:keys [app-state-key class-name]}]
  (fn [data owner]
    (reify
      ; ...
      om/IDidUpdate
      (did-update
        [this prev-props prev-state]
        (let [e (om/get-node (.-owner this))]
          (.log js/console "did-update" e)
          (.focus e)))
      ; ...
      )))

更新:如果仅更新组件状态,则会触发 IDidUpdate 生命周期事件 . 但是,如果应用程序状态发生更改,则不会触发(由于上面的 om/update! ) .

1 回答

  • 0

    一个潜在的解决方案是在你的om / root调用中使用core.async和 :tx-listen .

    :tx-listen 选项允许您指定在提供的应用程序状态更改时要调用的函数 - 因此我们提供一个函数,该函数写入附加了'pub'的通道 .

    然后,当您的组件安装时,您使用 IWillMount 订阅该通道上的事件,并在 IWillUnmount 上清除它 .

    显然,这里有一些清理的空间(特别是,您可能希望缩小组件所听取的事件类型) - 但它展示了基本的想法 .

    ....
    (defonce changes (chan))
    (defonce changes-pub (pub changes :msg-type))
    ....
    (om/root
       (input-component {:app-state-key :input-state
                         :class-name "theClass"})
       app-state
       {:target (. js/document (getElementById "app"))
        :tx-listen (fn [tx-data root-cursor]
                     (put! changes {:msg-type :state-updated}))})
    

    然后 - 在组件代码中,您可以订阅mount上的更改,并在卸载时关闭通道

    ...
       (reify    
          om/IWillMount
          (will-mount [_]
            (sub changes-pub :state-updated (:sub-chan (om/get-state owner)))
            (go-loop []
              (if-let [update (<! changes)]
                (let [node (om/get-node owner (name app-state-key))]
                  (println "Resetting focus")
                  (.focus node)
                  (recur)))))  
          om/IWillUnmount
          (will-unmount [_]
            (close! (:sub-chan (om/get-state owner))))
          om/IInitState
          (init-state 
            [this]
            {:text (data app-state-key)
             :sub-chan (chan)})
          ...
          )))
    

相关问题