This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-04-13
Channels
- # babashka (45)
- # babashka-sci-dev (15)
- # beginners (72)
- # biff (4)
- # calva (3)
- # clj-on-windows (67)
- # clj-otel (1)
- # cljfx (7)
- # clojure (74)
- # clojure-austin (1)
- # clojure-dev (4)
- # clojure-europe (6)
- # clojure-gamedev (1)
- # clojure-germany (5)
- # clojure-losangeles (6)
- # clojure-nl (3)
- # clojure-uk (6)
- # clojured (2)
- # clojurescript (42)
- # core-typed (2)
- # cursive (4)
- # emacs (18)
- # events (1)
- # fulcro (13)
- # humbleui (8)
- # introduce-yourself (2)
- # kaocha (11)
- # leiningen (5)
- # lsp (16)
- # malli (8)
- # off-topic (69)
- # pathom (38)
- # pedestal (3)
- # reagent (17)
- # releases (3)
- # shadow-cljs (10)
- # spacemacs (6)
- # sql (1)
- # tools-deps (5)
- # xtdb (20)
Hi there, is there a pattern to do like a useEffect listening to a prop change?
Simple exemple: I have a input type text with an internal state for the value. But I want it to be semi-controlled. So every time the props.value changed, I want to update my internal state. Like a useEffect(() => setValue(props.value), [props.value])
.
A native cljs/reagent solution I found was to store the props.value in a ratom, and do a (when (not= @old-props-value props-value) (reset! old-props-value props-value) (do-some-stuff-here))
Thanks if you can help!
The same use cases as the useEffect hook in React, I've provided one above. Was my example not clear?
It is! But what I'm trying to understand is that you want to track the value onChange but without using the onChange callback is that right?
the value is in the props so there's no on change callback
I literally want the equivalent of useEffect(() => setInternalValue(props.value), [props.value])
I may create myself an helper for these, or use React.useEffect directly, but I wanted to know if there's a native cljs/reagent solution for listening to a prop change
I don’t think there’s a native reagent solution for that. I’d just go with:
(defn component []
(r/useEffect (fn []
;; your logic in here
identity))
[:div
[:input
{:name "hello"}]
[:div "other stuff"]])
[:f> component]
The solution you found is not ideal because you’ll end up performing side effects in the render block.. If you don’t want to use the useEffect
hook, you could simply give your input an on-change
callback and it’ll remain uncontrolled as long as you don’t also give it a value
attribute.. I’d personally go with this approach
I don't want it to be uncontrolled. It needs a value to work. The real use case that I had is a code/edn editor. I give a edn structure as the value to my component. The component uses pprint and display it in a textarea. The on-change callback is called only when the user click on a button "apply changes". So there's an internal on-change loop when the user modify the edn, and then when the button is clicked it calls the props/on-change. I don't want to call the props/on-change each time the textarea area changes, because it performs a parse-string/pprint loop.
Thanks for you help, just wanted to be sure there's nothing native for that
(defn create-use-effect []
(let [previous-args (atom ::nil)]
(fn [fn args]
(when (not= @previous-args args)
(reset! previous-args args)
(apply fn args)))))
(defn component []
(let [use-effect (create-use-effect)
internal-value (r/atom nil)]
(fn [value]
(use-effect #(reset! internal-value %) [value]))))
Sometimes it is just easier to implement your own logic, I didn't tested it yet
doing side effects in render like you're doing may break in a future version of react
the "right way" to do it is to do useEffect
like Lu showed above and render the component via [:f> component ,,,]
so you can use hooks in it. or, to use a form 3 component and component-did-update
e.g.
(defn edn-editor
[data on-change]
(let [[text set-text] (react/useState
#(with-out-str (clojure.pprint/pprint data))]
;; TODO debounce on-change call
(react/useEffect
(fn []
(on-change (edn/read-string text))
js/undefined)
#js [text])
;; update text state when `data` prop changes
(react/useEffect
(fn []
(set-text
(with-out-str
(clojure.pprint/pprint data)))
js/undefined)
#js [data])
[:textarea
{:value text
:on-change #(set-text (.. % -target -value))}]))
Yes, thanks. I think that's near the limitations of reagent, it's not very complient with modern React. I discovered UIx and I think I will migrate to it when I have the time.