I have an text input element that uses component state and application state.
In the example shown in React: More About Refs, the goal is to call focus
on the element after re-rendering. Here is the key part, done with JS in React.
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!
});
},
I want to do something similar with Om. I've noticed neither
Om's
set-state!
(for changing component state; see the docs and source), norOm's
update!
(for changing application state; see the docs and source)
provides ways to specify a callback. So I'm looking for other ways to cause something to happen later, after a re-render.
Here's my example:
(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')))))
(Note: parse-int
, not shown, "cleans up" the component state so that it is suitable for the application state.)
Changing the text input's component state doesn't cause it to lose focus, but mutating the application state does.
I've tried using core.async channels, but that does not seem to help because I only want the callback to happen after the re-render has completed.
I also tried using IDidUpdate
, like this:
(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)))
; ...
)))
Update: The IDidUpdate
lifecycle event does fire if only the component state is updated. However, it does not fire if the application state changes (due to om/update!
, above).