This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-04-06
Channels
- # beginners (95)
- # boot (3)
- # cider (13)
- # cljs-dev (9)
- # cljsjs (1)
- # cljsrn (35)
- # clojure (78)
- # clojure-dev (5)
- # clojure-italy (6)
- # clojure-nl (9)
- # clojure-russia (13)
- # clojure-spec (1)
- # clojure-uk (74)
- # clojurescript (59)
- # community-development (6)
- # core-async (41)
- # css (110)
- # data-science (2)
- # datomic (22)
- # defnpodcast (1)
- # devcards (1)
- # docs (1)
- # editors (6)
- # emacs (51)
- # figwheel (1)
- # fulcro (66)
- # jobs (1)
- # jobs-discuss (75)
- # lumo (51)
- # mount (2)
- # off-topic (33)
- # pedestal (24)
- # proton (3)
- # re-frame (29)
- # reagent (92)
- # reitit (16)
- # shadow-cljs (16)
- # spacemacs (4)
- # specter (6)
- # vim (6)
- # yada (7)
doesn’t react guarantee that the ref callback is done before did-mount? I have a normal kind of ref call back :ref #(swap! state assoc :div-node %)
but sometimes in my component-did-mount
that :div-node
is empty
okay i guess an empty chat channel can operate as a rubber ducky. i figured it out. 🦆
When the silence quacks back
I'd like to disagree. But I can't :-)
that’s actually true… i got bit by the ol’ load-stuff-in-your-component anti-pattern but i swear i had a good reason
@lee.justin.m what ended up being the problem?
(not that the ref callback is called with nil
on unmount)
@pesterhazy oh I had a placeholder div while the data was loading. the ref was attached to the non-placeholder div. so something like (if (nil? @thing) [:div placeholder] [:div {:ref ref-cb}]
. in component-did-mount I was rendering to a canvas if the data was loaded, other wise i was loading the data from server and then rendering. but occasionally, the data would come back and the render func would be called before the divs would get re-rendered. i didn’t think that was possible because i assumed the loading of the data would cause an atom-based re-render of the divs first. apparently you can’t rely on that. maybe due to the batching logic?
or maybe due to the fact that i was already in component-did-mount and it can’t be re-entered. not sure.
hi again all--I think this must be a basic question but some googling around didn't help me. I'm writing a form-2 and this is what I tried first:
(let [state (r/atom default-form-state)]
(fn []
[:form {:on-submit #(js/console.log "Submit")}
[ui/text-field {:on-change #(swap! state assoc :name %2)}]]))
This causes visible UI lag, though--the rendering of the entered char is delayed until the atom is updated, I think, which causes input lag of ~100ms. I tried debouncing the function, which allowed for a better result, but this code smells:
(let [state (r/atom default-form-state)]
(fn []
[:form {:on-submit #(js/console.log "Submit")}
[ui/text-field {:on-change (goog.functions.debounce #(swap! state assoc :name %2) 100)}]]))
Any suggestions?@lee.justin.m 1) wrapped in a defn:
(defn new-project-dialog-form
[submit-callback]
(let [state (r/atom default-form-state)]
(fn []
[:form {:on-submit #(js/console.log "Submit")}
[ui/text-field {:floating-label-text "Project name"
:error-text (name-error-text (:name @state))
:on-change (goog.functions.debounce #(swap! state assoc :name %2) 100)}]
])))
2) within another component:
(defn- new-project-dialog []
(let [open (rf/subscribe [::new-project-dialog-open])]
[ui/dialog {:title "Create a new project"
:modal false
:open @open
:actions (r/as-element new-project-dialog-actions)
:on-request-close close-dialog}
[new-project-dialog-form]]))
hm okay that looks right (though I don’t know about reframe). you should definitely not be seeing 100ms delays. my instinct is that something is causing re-renders. try this
(defn new-project-dialog-form
[submit-callback]
(let [state (r/atom default-form-state)]
(js/console.log "new-project-dialog-form: new component")
(fn []
(js/console.log "new-project-dialog-form: render")
[:form {:on-submit #(js/console.log "Submit")}
[ui/text-field {:floating-label-text "Project name"
:error-text (name-error-text (:name @state))
:on-change (goog.functions.debounce #(swap! state assoc :name %2) 100)}]])))
you should only get a new component once, and then a single render for each keypress
That was the output for typing in "qweqweqweqwe" for the code you gave me (minus debounce). Still saw the input lag
It's implemented in JS though I'm accessing it from a cljs wrapper: https://github.com/mui-org/material-ui/blob/v1-beta/src/TextField/TextField.js https://github.com/madvas/cljs-react-material-ui/tree/master/src/cljs_react_material_ui
with this:
(defn new-project-dialog-form
[submit-callback]
(let [state (r/atom default-form-state)]
(js/console.log "new-project-dialog-form: new component")
(fn []
(js/console.log "new-project-dialog-form: render")
[:form {:on-submit #(js/console.log "Submit")}
[:input {:type "text" :on-change #(swap! state assoc :name (-> % .-target .-value))}]
])))
haha, well thanks for the help regardless. a bit surprised that TextField is apparently so slow
I guess I'll just write a macro that will debounce all my validator functions unless the material-ui crowd has a suggestion :man-shrugging:
material-ui wraps an input element, masking it to reagent so it can't work its ratom-to-input magic
could that be it?
the topic was discussed a few days/weeks ago, it might be worth checking the logs
in #reagent
@pesterhazy perhaps--FWIW I'm using the 0.x material-ui (nobody's made a clojurescript wrapper for 1.x yet). I found this issue and they claim to have fixed perf in the 1.x branch https://github.com/mui-org/material-ui/issues/5121
there are known issues with reagent and 3rd party input fields
do you need a controlled component? If not you might just switch to an uncontrolled component (for <Input> that would be using defaultValue
rather than value
)
@lee.justin.m that's correct
oh, then it can't be the issue I'm thinking of
doesn't it have to be an issue with material-ui then?
the reagent controlled input issue should cause things like jumping cursors and dropped characters. it really shouldn’t cause a 100ms delay
unless you're hogging the event loop with computation
i'd boil it down to a minimal repro case. just keep cutting stuff until the problem goes away
@pesterhazy not sure if you saw it up there but i tried replacing the mui component with a regular <input>
element and the problem disappeared. i could probably dig in deeper but it seems likely that there's just a problem with how the component implements on-change
if you replace the on-change handler with (fn [])
does the problem go away as well?
it might be that the input element gets unmounted and remounted on every keystroke — that might explain the problem
oh, sorry 🙂
something that might be interesting: TextField contains an element that holds the value of the errorText
proprety. I was feeding that a function of my state, so it was updating with every call to on-change
event. Removing that label got rid of the lag I was seeing
Sounds like you found the solution
My current recommendation for custom inputs on Reagent (and even just built-in inputs) is to debounce on-change/or disable on-change if the input has focus or something, so that the input is uncontrolled when input is focused, and controlled else (so input value updates if state is updated). Based on tests I've done with Material-UI 0 and 1, the workaround Reagent uses for native inputs can't be implemented for custom inputs.
This is currently the only thing blocking 0.8 release, I'm trying to understand if I should revert the synthetic-input thing that was introduced but which I think doesn't solve anything. If I find a solution I'll add MaterialUI 0/1 and React-bootstrap examples to Reagent examples folder and write a doc about this.
I'm also waiting to see what will be official React solution for these cases when they start supporting async rendering.
Very interesting
Removing code, even hacks of course has the potential to break existing code
The code was added in 0.8-alpha2 and I doubt it is really used elsewhere than one work project where I tried to use it.
Oh I thought you meant something older than that
Removing the feature will change function arity so it will be compile time error if it is removed, so no silent breakage.
Changing from an alpha is totally fine
I'm not changing how the workaround that used for native inputs, just the option that tried to make it available for custom inputs.
Gotcha
It’s a fundamental problem that ratoms don’t work well with input fields
Brain dump about controlled inputs & the problem: https://gist.github.com/Deraen/762351365ac04b2057ef5f726342fd1a
I guess it works in React because people use this.state
I thought this comment by Dustin Getz was interesting: https://www.reddit.com/r/Clojure/comments/87psf9/comment/dwez2u9
The comparison to redux is useful
My understanding is that it works with React because it doesn't use RAF, and it doesn't work there either if they would use RAF
But I still don't understand RAF/async rendering well enough to describe what it does (or how it works, and why it is good idea/or I'm not sure if it is a good idea)
But seeing that React team is looking into it, there is probably some value on implementing it correctly
Agreed
But React's solution could be "you are handling the updates incorrectly (updating on each key-press), you shouldn't do it like that"
The fact remains that input value needs to update in the same tick as the change event
I feel I don’t understand the requirements 100%