Проблема с автозаполнением (Material UI + React + Reagent/ClojureScript)

У меня проблема с использованием Autocomplete пользовательского интерфейса материалов с реагентом (ClojureScript). Элемент отображается нормально, но когда я пытаюсь щелкнуть по нему, я получаю следующие исключения:

Uncaught TypeError: Cannot read property 'focus' of null
    at handleClick (useAutocomplete.js:938)
    at HTMLUnknownElement.callCallback (react-dom.development.js:189)
    at Object.invokeGuardedCallbackImpl (react-dom.development.js:238)
    at invokeGuardedCallback (react-dom.development.js:293)
    at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:307)
    at executeDispatch (react-dom.development.js:390)
    at executeDispatchesAndReleaseTopLevel (react-dom.development.js:412)
    at forEachAccumulated (react-dom.development.js:3260)
    at runEventsInBatch (react-dom.development.js:3305)
    at handleTopLevel (react-dom.development.js:3515)

useAutocomplete.js:322 Uncaught TypeError: Cannot read property 'removeAttribute' of null
    at eval (useAutocomplete.js:322)
    at eval (useEventCallback.js:26)
    at eval (useAutocomplete.js:433)
    at eval (useEventCallback.js:26)
    at eval (useAutocomplete.js:463)
    at eval (useAutocomplete.js:528)
    at commitHookEffectListMount (react-dom.development.js:19765)
    at commitPassiveHookEffects (react-dom.development.js:19803)
    at HTMLUnknownElement.callCallback (react-dom.development.js:189)
    at Object.invokeGuardedCallbackImpl (react-dom.development.js:238)

Взломав отладчик JS, я вижу, что inputRef.current имеет значение null (это то, к чему вызываются focus и removeAttribute. (Как ни странно, единственное место, где inputRef устанавливается в файле, - это вызов useRef(null), что приводит к тому, что inputRef.current является нулевым. )

В моем коде я определяю поле автозаполнения следующим образом:

(ns my-product-redacted.views.atoms
  (:require [reagent.core :as r]
            ["@material-ui/lab/Autocomplete" :default Autocomplete]
            ;; other requires
  ))

(def autocomplete-field (r/adapt-react-class Autocomplete))

Затем в компоненте React он используется следующим образом:

[a/autocomplete-field {:render-input      (fn [js-params]
                                            (let [clj-params (js->clj js-params)
                                                  params     {:label             label
                                                              :width             width
                                                              :select            select?
                                                              :Input-label-props {:shrink true}
                                                              :Select-props      {:native true}}
                                                  all-params  (into clj-params params)]
                                               (js/console.log (clj->js all-params))
                                               (r/as-element [a/text-field all-params])))
                       :options          (when select? (cons {:value "" :label ""} options))
                       :get-option-label (fn [option] (or (get (js->clj option) "label") ""))
                       :default-value    (when (not select?) value-override)
                       :value            (when select? value)
                       :disabled         disabled?
                       :on-focus         #(re-frame/dispatch [::forms/on-focus path])
                       :on-blur          #(re-frame/dispatch [::forms/on-blur path])
                       :on-change        #(re-frame/dispatch (conj on-change (-> % .-target .-value)))})]

(Здесь a/text-field также определяется в том же пространстве имен, что и a/autocomplete-field, и аналогичным образом.)

Журнал консоли JS (из вызова (js/console.log (clj->js params))) показывает, что inputProps.ref.current имеет значение null. Однако InputProps.ref не равно нулю. Тем не менее, я попытался вручную связать ту же функцию, которая передается с InputProps.ref на inputProps.ref.current, но это не имело никакого значения.

Я также попробовал обходной путь, предложенный в https://github.com/mui-org/material-ui/issues/21245 (хотя эта проблема связана с библиотекой Gestalt, а не с Reagent, это предполагает, что может быть проблема с пересылкой ссылок). Но перенос text-field в div с ref, взятым из InputProps.ref, также не имел значения.

Какие-либо предложения?


person silverberry    schedule 17.09.2020    source источник


Ответы (1)


Вызов js->clj для js-параметров рендеринга нарушает их.

Я поместил краткую демонстрацию компонента автозаполнения пользовательского интерфейса материала в свой демонстрационный репозиторий здесь.

Но в основном это взято из официальной документации/примеров реагентов L93" rel="noreferrer">здесь:

(defn autocomplete-example []
  [:> mui/Grid
   {:item true}
   [:> Autocomplete {:options ["foo" "bar" "foobar"]
                     :style {:width 300}
                     ;; Note that the function parameter is a JS Object!
                     ;; Autocomplete expects the renderInput value to be function
                     ;; returning React elements, not a component!
                     ;; So reactify-component won't work here.
                     :render-input (fn [^js params]
                                     ;; Don't call js->clj because that would recursively
                                     ;; convert all JS objects (e.g. React ref objects)
                                     ;; to Cljs maps, which breaks them, even when converted back to JS.
                                     ;; Best thing is to use r/create-element and
                                     ;; pass the JS params to it.
                                     ;; If necessary, use JS interop to modify params.
                                     (set! (.-variant params) "outlined")
                                     (set! (.-label params) "Autocomplete")
                                     (r/create-element mui/TextField params))}]])
person dakra    schedule 20.09.2020