Skip to content

Instantly share code, notes, and snippets.

@metametadata
Last active June 6, 2017 07:56
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save metametadata/3b4e9d5d767dfdfe85ad7f3773696a60 to your computer and use it in GitHub Desktop.
Save metametadata/3b4e9d5d767dfdfe85ad7f3773696a60 to your computer and use it in GitHub Desktop.
Fixing of caret/cursor jumps in text inputs of cljsjs.react-bootstrap
(ns app.components.react-bootstrap
(:require [cljsjs.react-bootstrap]
[reagent.core :as r]))
(def Alert (r/adapt-react-class (.-Alert js/ReactBootstrap)))
(def Button (r/adapt-react-class (.-Button js/ReactBootstrap)))
; ...
(def FormControl (r/adapt-react-class (.-FormControl js/ReactBootstrap))) ; WARNING: use FormControlFixed for text input controls instead
(defn FormControlFixed
"FormControl without cursor jumps in text/textarea elements. Problem explained:
https://stackoverflow.com/questions/28922275/in-reactjs-why-does-setstate-behave-differently-when-called-synchronously/28922465#28922465
I haven't tested it much in IE yet, so if it breaks in IE see this: https://github.com/tonsky/rum/issues/86
Usage example:
[FormControlFixed {:type :text
:value @ui-value
:max-length 10
:on-change #(on-change-text (.. % -target -value))}]"
[{:keys [value on-change] :as _props}]
{:pre [(ifn? on-change)]}
(let [local-value (atom value)] ; regular atom is used instead of React's state to better control when renders should be triggered
(r/create-class
{:display-name "FormControlFixed"
:should-component-update (fn [_ [_ old-props] [_ new-props]]
; Update only if value is different from the rendered one or...
(if (not= (:value new-props) @local-value)
(do
(reset! local-value (:value new-props))
true)
; other props changed
(not= (dissoc new-props :value)
(dissoc old-props :value))))
:render (fn [this]
[FormControl (-> (r/props this)
; use value only from the local atom
(assoc :value @local-value)
(update :on-change
(fn wrap-on-change [original-on-change]
(fn wrapped-on-change [e]
; render immediately to sync DOM and virtual DOM
(reset! local-value (.. e -target -value))
(r/force-update this)
; this will presumably update the value in global state atom
(original-on-change e)))))])})))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment