This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-03-21
Channels
- # announcements (1)
- # aws-lambda (62)
- # babashka (116)
- # beginners (67)
- # chlorine-clover (39)
- # cider (10)
- # cljs-dev (5)
- # clojure (30)
- # clojure-austin (2)
- # clojure-europe (2)
- # clojure-italy (6)
- # clojure-nl (24)
- # clojure-uk (28)
- # clojurescript (33)
- # data-science (6)
- # datascript (10)
- # datomic (5)
- # duct (39)
- # emacs (1)
- # events (8)
- # fulcro (9)
- # graalvm (29)
- # hoplon (7)
- # juxt (10)
- # malli (4)
- # off-topic (6)
- # pathom (10)
- # perun (1)
- # reagent (45)
- # shadow-cljs (5)
- # sql (14)
- # tools-deps (10)
- # xtdb (9)
Hello, is there a better way of filtering a list in a reaction
, is it okay to use doall
?
(defn my-component []
(let [foo (r/atom [1 2 3])
bar (r/atom 2)
baz (reaction (doall (filter #(> % @bar) @foo))) ]
(fn []
....))
doall
should be fine. You can also use (into [] (filter ...) @foo)
if you need a vector - it uses a transducer, so it should be more efficient.
awesome thanks mate!
Hi, I am trying to wrap Autocomplete component from Material-ui in Reagent: https://material-ui.com/components/autocomplete/. Here is their example code:
<Autocomplete
id="free-solo-demo"
freeSolo
options={top100Films.map(option => option.title)}
renderInput={params => (
<TextField {...params} label="freeSolo" margin="normal" variant="outlined" />
)}
/>
I am wrapping this like this:
[:> Autocomplete {:options options
:getOptionLabel get-option-label
:renderOption render-option
:freeSolo true
:renderInput (fn [params]
(r/reactify-component [:> TextField (assoc (js->clj params)
:label label
:variant "outlined"
:on-change on-change)]
In particular, I am not sure how renderInput should be wrapped. It does not display any error but the component is empty, not showing anything.Thx, that helped. What is the difference?
Docstrings to the rescue. :) The first one is to convert Reagent components (i.e. CLJS functions). The second one is to convert Hiccup to React elements.
I see.
It still fails when I try to click on the text field:
useAutocomplete.js:180 Uncaught TypeError: Cannot read property 'removeAttribute' of null
at useAutocomplete.js:180
at useEventCallback.js:26
at useAutocomplete.js:400
at useEventCallback.js:26
at useAutocomplete.js:426
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)
at invokeGuardedCallback (react-dom.development.js:293)
(anonymous) @ useAutocomplete.js:180
(anonymous) @ useEventCallback.js:26
(anonymous) @ useAutocomplete.js:400
(anonymous) @ useEventCallback.js:26
(anonymous) @ useAutocomplete.js:426
commitHookEffectListMount @ react-dom.development.js:19765
commitPassiveHookEffects @ react-dom.development.js:19803
callCallback @ react-dom.development.js:189
invokeGuardedCallbackImpl @ react-dom.development.js:238
invokeGuardedCallback @ react-dom.development.js:293
flushPassiveEffectsImpl @ react-dom.development.js:22885
exports.unstable_runWithPriority @ scheduler.development.js:654
runWithPriority$1 @ react-dom.development.js:11062
flushPassiveEffects @ react-dom.development.js:22852
performSyncWorkOnRoot @ react-dom.development.js:21769
(anonymous) @ react-dom.development.js:11112
exports.unstable_runWithPriority @ scheduler.development.js:654
runWithPriority$1 @ react-dom.development.js:11062
flushSyncCallbackQueueImpl @ react-dom.development.js:11107
flushSyncCallbackQueue @ react-dom.development.js:11095
Internals.Events @ react-dom.development.js:21925
dispatchDiscreteEvent @ react-dom.development.js:1072
react_devtools_backend.js:6 The above error occurred in the <ForwardRef> component:
in ForwardRef (created by WithStyles(ForwardRef))
in WithStyles(ForwardRef) (created by orgpad.client.views.widgets.suggestions.suggestions)
in orgpad.client.views.widgets.suggestions.suggestions (created by orgpad.client.views.share_orgpage.users)
in orgpad.client.views.share_orgpage.users (created by orgpad.client.views.share_orgpage.share_orgpage_dialog)
in orgpad.client.views.share_orgpage.share_orgpage_dialog (created by orgpad.client.views.widgets.md_dialog.md_dialog)
in div (created by ForwardRef)
in ForwardRef (created by WithStyles(ForwardRef))
in WithStyles(ForwardRef) (created by orgpad.client.views.widgets.md_dialog.md_dialog)
in div (created by ForwardRef)
in ForwardRef (created by WithStyles(ForwardRef))
in WithStyles(ForwardRef) (created by ForwardRef)
in div (created by Transition)
in Transition (created by ForwardRef)
in ForwardRef (created by TrapFocus)
in TrapFocus (created by ForwardRef)
in div (created by ForwardRef)
in ForwardRef (created by ForwardRef)
in ForwardRef (created by ForwardRef)
in ForwardRef (created by WithStyles(ForwardRef))
in WithStyles(ForwardRef) (created by orgpad.client.views.widgets.md_dialog.md_dialog)
in orgpad.client.views.widgets.md_dialog.md_dialog (created by orgpad.client.views.share_orgpage.share_orgpage)
in orgpad.client.views.share_orgpage.share_orgpage (created by orgpad.client.views.root.modal_dialogs)
in orgpad.client.views.root.modal_dialogs (created by root-component)
in div (created by root-component)
in div (created by root-component)
in root-component (created by orgpad.client.views.root.root)
in orgpad.client.views.root.root
Consider adding an error boundary to your tree to customize error handling behavior.
Visit to learn more about error boundaries.
r @ react_devtools_backend.js:6
logCapturedError @ react-dom.development.js:19561
logError @ react-dom.development.js:19598
expirationTime.callback @ react-dom.development.js:20742
commitUpdateQueue @ react-dom.development.js:12513
commitLifeCycles @ react-dom.development.js:19917
commitLayoutEffects @ react-dom.development.js:22835
callCallback @ react-dom.development.js:189
invokeGuardedCallbackImpl @ react-dom.development.js:238
invokeGuardedCallback @ react-dom.development.js:293
commitRootImpl @ react-dom.development.js:22573
exports.unstable_runWithPriority @ scheduler.development.js:654
runWithPriority$1 @ react-dom.development.js:11062
commitRoot @ react-dom.development.js:22413
performSyncWorkOnRoot @ react-dom.development.js:21839
(anonymous) @ react-dom.development.js:11112
exports.unstable_runWithPriority @ scheduler.development.js:654
runWithPriority$1 @ react-dom.development.js:11062
flushSyncCallbackQueueImpl @ react-dom.development.js:11107
flushSyncCallbackQueue @ react-dom.development.js:11095
Internals.Events @ react-dom.development.js:21925
dispatchDiscreteEvent @ react-dom.development.js:1072
react-dom.development.js:11125 Uncaught TypeError: Cannot read property 'removeAttribute' of null
at useAutocomplete.js:180
at useEventCallback.js:26
at useAutocomplete.js:400
at useEventCallback.js:26
at useAutocomplete.js:426
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)
at invokeGuardedCallback (react-dom.development.js:293)
Not sure whether the transformation I do on params is correct.
Yep, I've seen it as well in my own attempt to understand what was wrong. No clue, sorry.
I got it working like this
:renderInput (fn [props] (r/create-element Textfield props))
Where Textfield
is a native React component imported like this ["@material-ui/core/Textfield" :default Textfield]
(shadow-cljs)@U6N4HSMFW Do you have any idea why as-element
does not work, what it does "wrong"?
First I dabbled with as-element
and reactify-component
but it turned out to be simpler to just not jump from âreact-worldâ into âreagent-worldâ
Iâm not sure, but my best guess is that props
is a js-object and you need to clj->js
it and it looses the ref there for some reason.
Maybe @U061V0GG2 could give us the proper answer đ
I got it to render with (r/as-element [:> Textfield (js->clj props)])
but ref was lost or something and it died when trying to open the select list.
Huh, yeah.
With reactify-component
(.. props -inputProps -ref -current)
is the <input>
element. And with as-element
it somehow becomes null
. Even before we return from the function.
Nothing obviously wrong here. hmh.
You can try (r/reactify-component (fn [props] [:> TextField ...]))
That would be the correct way to use reactify-component, give the Reagent component as the parameter, not the elements vector.
Hmm, probably not. Bare function and as-element
should be best way here, as it doesn't try converting props.
Or hm, as-element also might do some conversion.
You could try (fn [props] (r/create-element TextField props))
yes that's it probably. as-element
will do some props conversion, but create-element
is just the React createElement
call
Oh, right... You cannot convert props at all if you're using react/createRef
. Because that mechanism expects that the underlying JS object is mutable.
@U6N4HSMFW It does some custom version of clj->js
. And we also do the regular js->clj
. Thus, the ref object is not the same. Any mutation to it is not visible to the component that has set the ref in the first place.
as-element
and reactify-component
do the same clj props map to js props map conversion, it might have some inference with Classes it doesn't know about
https://github.com/reagent-project/reagent/blob/master/src/reagent/impl/template.cljs#L62-L69 the first check probably only works for Plain Old Objects
But even if clj->js
is called for the ref value, it doesn't change it
@U061V0GG2 It's not about changing the value, it's about changing the holding object. TextField
is expected to call something like ref.current = this
in the depths of React. And if ref
is a new object created by clj->js
or the like, the Autocomplete
component will never see the change.
I might convert Reagent material-ui example to Shadow-cljs later and investigate more. Currently I don't have project with material-ui/labs running.
(let [a (react/createRef)]
(js/console.log (identical? a (clj->js a))))
This prints true
, ref object should be the same object still
To put it in other words - the above example will not work in raw React if you do something like props = deepCopy(props)
.
But if there is JS props -> clj props map conversion somewhere, that could do something else
Oh, duh - it doesn't work because it's not supposed to work with plain objects. It turns props
into {children: props}
.
I think, the case can be closed. :)
So if you use js->clj
that will definitely convert ref object to Cljs map, which break it
Example here: https://github.com/reagent-project/reagent/blob/master/examples/material-ui/src/example/core.cljs#L75-L90
Autocomplete expects renderInput to be function returning React elements, not component. That might explain why reactify-component doesn't work, it returns class component.
Thx a lot for figuring this out.