渲染后的Om回调(在更改应用程序状态之后聚焦元素)
问题描述:
我有一个使用组件状态和应用程序状态的文本输入元素。渲染后的Om回调(在更改应用程序状态之后聚焦元素)
在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做类似的事情。我注意到既不
提供了指定回调的方法。因此,我正在寻找其他方法,以便在重新渲染后在稍后发生某些事情。
这是我的例子:
(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
,未示出,“清理”该组件状态,使得它适合于应用程序的状态。)
改变文本输入的分量状态不会导致它失去焦点,但会改变应用程序状态。
我试过使用core.async频道,但似乎没有帮助,因为我只想在重新呈现完成后发生回调。
(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
,这样的尝试的IDidUpdate
生命周期事件确实火如果只有部分状态更新。但是,如果应用程序状态更改(由于上述om/update!
),它不会触发。
答
一个潜在的解决方案就是在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}))})
然后 - 在组件代码,您可以订阅山的变化,并关闭在卸载
...
(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)})
...
)))
我很好奇,为什么'IDidUpdate'不火的通道。在初始渲染之后它不会触发,所以我假定你的意思是在输入元素被修改之后它不会触发。 – 2014-09-21 19:23:33
我刚刚更新了最后一段:在修改组件状态后,我确实看到了'IDidUpdate'触发。但是,就我而言,它并没有在应用程序状态发生变化之后;这让我觉得如果一个组件被销毁并重新创建,那么'IDidUpdate'不会触发。 – 2014-09-21 20:21:15
这可能是发生了什么事。如果某个组件被销毁,那么正在安装一个新组件。在这种情况下,您需要'IDidMount'来代替。 – 2014-09-22 01:21:37