2.4 KiB
Material-UI
Material-UI TextField has for long
time caused problems for Reagent users. The problem is that TextField
wraps the
input
element inside a component so that Reagent is not able to enable
input cursor fixes, which are required due to async rendering.
Good news is that Material-UI v1 has a property that can be used to provide
the input component to TextField
:
(ns example.material-ui
(:require ["material-ui" :as mui]
[reagent.core :as r]))
(def text-field (r/adapt-react-class mui/TextField))
(def value (r/atom ""))
(def input-component
(r/reactify-component
(fn [props]
[:input (-> props
(assoc :ref (:inputRef props))
(dissoc :inputRef))])))
(def example []
[text-field
{:value @value
:on-change #(reset! value (.. e -target -value))
:InputProps {:inputComponent input-component}}])
reactify-component
can be used to convert Reagent component into React component,
which can then be passed into Material-UI. The component should be created once
(i.e. on top level) to ensure it is not unnecessarily redefined, causing the
component to be re-mounted.
For some reason Material-UI uses different name for ref
, so the inputRef
property
should be renamed by the input component.
Wrapping for easy use
Instead of providing :InputProps :inputComponent
option to every TextField
,
it is useful to wrap the TextField
component in a way that the option is added always:
(defn text-field [props & children]
(let [props (-> props
(assoc-in [:InputProps :inputComponent] input-component)
rtpl/convert-prop-value)]
(apply r/create-element mui/TextField props (map r/as-element children))))
Here r/create-element
and reagent.impl.template/convert-prop-value
achieve
the same as what adapt-react-class
does, but allows modifying the props.
Check the example project for complete code. Some additional logic is
required to ensure option like :multiline
and :select
work correctly,
as they affect how the inputComponent
should work.
TODO: :multiline
TextField
without :rows
(i.e. automatic height) doesn't
work, because that requires Material-UI Input/Textarea
, which doesn't work
with Reagent cursor fix.