This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-10-28
Channels
- # announcements (5)
- # babashka (7)
- # beginners (101)
- # biff (9)
- # calva (46)
- # cider (6)
- # clj-yaml (2)
- # cljsrn (13)
- # clojure (11)
- # clojure-europe (43)
- # clojure-nl (13)
- # clojure-norway (22)
- # clojurescript (20)
- # conjure (1)
- # cursive (7)
- # data-science (2)
- # datomic (26)
- # emacs (38)
- # graphql (27)
- # gratitude (5)
- # hoplon (8)
- # hugsql (22)
- # humbleui (2)
- # hyperfiddle (6)
- # introduce-yourself (8)
- # joyride (3)
- # lsp (79)
- # malli (6)
- # nbb (67)
- # portal (16)
- # rdf (27)
- # reagent (42)
- # releases (2)
- # remote-jobs (1)
- # shadow-cljs (36)
- # test-check (17)
- # tools-deps (1)
- # xtdb (15)
Question: is there some utility code in reagent for identifying props like :on-click
, etc, prefixed with :on-
, or are those automatically camel-cased on the way into react and not explicitly handled?
not sure if this is exactly what you're asking but reagent automatically converts the standard props hooks on hiccup components to camelCase<->kebab-case for you. This only becomes an issue if you're using 3rd party components with reagent/adapt-react-class
, where you may end up having to use camelCase. e.g., antd and material-ui components I will use :onClick
instead of :on-click
. Yes, I could write a wrapper, but I have things to do so I write :onClick
and keep it movin'
so to be more explicit,
(defn standard-reagent-component []
[:button {:on-click #(println "works")} "Click Me"])
(def antd-button (reagent/adapt-react-class (.. antd -Button))
(defn antd-button []
[antd-button {:onClick #(println "this works")} "No click me"])
ah I forgot you're writing a library
and you're looking to do the same trick
this is the actual answer to your question: https://github.com/reagent-project/reagent/blob/master/src/reagent/impl/component.cljs#L270
That is helpful! Yeah in this case I need to pull them out and register them as event handlers
Ugh, I am realizing that I still probably do want to use force-update to make my API cleaner. Passing these props to children to force a re-render is not great for folks writing new components. Is there a reliable way to force a render call to every child of a component if the component’s render is called? Maybe the question is really “in what lifecycle method is one supposed to call force-update?”
first of all I'm certainly no stickler for convention or common wisdom but I am obligated as a member of the neckbeard guild to say that "way lies madness" and ask if there's a reason that the rerender can't be done with the normal dataflow concerns?
if there is, happy to go down that rabbit-hole but is kind of a fragile rabbit-hole
that being said you might be doing it conceptually correctly already -- there's a number of "gotchas" with rendering components in reagent
and it's different pre-version 0.8, and then again different after I think 1.0 or 1.1
so for instance in current reagent,
(defn form-1
[data]
[:div
[:p (str "My data is: " data)]
[form-1-subcomponent-1 data]
[form-1-subcomponent-2 data]
[form-1-subcomponent-3 data]])
this should cause a rerender of all subcomponentswhen the value of data
changes
does that not work in your case?
I am constitutionally 100% on board with the dataflow model; the “issue” here I am trying to avoid for users comes from 2 things, as background. 1. scenes are build with big calls like like
var board = JXG.JSXGraph.initBoard('jxgbox',{boundingbox:[-5,5,5,-5]});
var A = [], s = [], B = [], c = [], r = [], k;
var attA = {name:'',strokeColor: '#7355ff', fillColor: '#7355ff'};
A[0] = board.create('point', [2.5, -3], attA);
A[1] = board.create('point', [2, 4], attA);
A[2] = board.create('point', [-2.5, 3], attA);
A[3] = board.create('point', [-4, -2], attA);
A[4] = board.create('point', [0, -4], attA);
and look like
http://jsxgraph.org/wiki/index.php?title=A_5-circle_incidence_theorem
instead of numbers, points can depend on the names of previous points for their coordinates. so really any time ANY point’s props change, the thing to do is remove everyone and re-add everyone to the board(because the dependency tree is not really usable for this)
oh lord
so you are completely right; the right thing to do is just pass a changed property to everyone and they will all re-render
ok so I'm thinking you might want to consider not using reagent subcomponents at all for the points, unless there is some reason to do that
I'm thinking you might want a form-3 component as the top level for the board and then using procedural calls to manipulate the board itself when the data changes
the thing I was trying to avoid was this. when I make a component that, say, adds multiple points, building on the Point
primitive, I have to do this:
(defn PointLine [x props]
(letfn [(f [i]
[Point [(- i) i]
(assoc props
:name (str i)
:strokecolor "red")])]
(into [:<>] (map f) (range x))))
if the user forgets to pass on the props
then these points won’t be able to trigger updatesUnless there are major performance concerns I'd probably just wipe the whole board and reinstantiate it from the new data
@U3BALC2HH yeah absolutely, that is functionally what is happening here. it’s just so nice to have the user PRETEND they are doing the declarative thing:
(v/html
[:<>
[jsx/JSXGraph {:boundingbox [-8 4 8 -5]
:showCopyright false
:axis true}
[jsx/Point [x y] {:name "A" :strokecolor "red" :on-drag on-drag}]
[jsx/Point [-xf -yf] {:name "B" :strokecolor "red"}]
[jsx/Point [0 0] {:name "C" :strokecolor "blue" :on-drag on-drag}]
[jsx/Angle ["A" "C" "B"] {}]]
[v/inspect @!state]])
have you considered something though like
(def board [board-data]
...)
where board-data
is a map?then they could be actually doing a declarative think, like the comp-viz and data-viz guys I think, it's been awhile and I can't remember the names of all the slick sci-cloj visualization libraries
@U3BALC2HH say more; what would be inside that function?
or that is supposed to be a def
, so they are actually writing a data structure that I then parse and turn into board.create
calls
stand by
yeah, that is actually my next step; • the user will write something like that on a server • I will (using #C035GRLJEP8) send that over to the browser • I will then expand it out into these reagent components And the reason I am doing the reagent thing is that I want to be able to stuff a jsxgraph instance into an existing reagent render tree, so users can build rich interfaces with this stuff
I think you are right that, given the state of things, I should accept that I am going to have to change the props and not try to stray further from the good road here
(defn board [board-data]
(let [active-board-data (reagent/atom board-data)
board-ref (reagent/atom nil)]
(letfn [(update-board-data! []
(let [current-board @board-ref
]
;; implementation tbd
(wipe-board! current-board)
(draw-board! current-board @active-board-data)))
(board-init [this]
(when-let [dom-node (reagent.dom/dom-node this)]
(reset! board-ref dome-node)))])
(reagent/create-class
{:display-name "board"
:component-did-mount (fn [this props]
(board-init this)
(update-board-data))
:component-did-update update-board-data
:reagent-render
(fn [board-data]
[v/html
[:<>
[jsx/JSXGraph {:boundingbox [-8 4 8 -5]
:showCopyright false
:axis true}]]])})))
so I don't know the API/details but that's kind of the gist of it
you'd probably have to stick some :onClick or some other handlers on there to manipulate active-board-data
and fiddle with one or two other things -- that's def more pseudocode than working code, but that's the gist of it
if efficiency became a thing you could diff the new map against the old map and do your own modifications but I doubt that's an issue unless you're dealing with a ton of data
also I just copy/pasta'd a bunch of your code, I don't know what v/
is or jsx/JSXGraph
so would that work or do you think you still need to go down the reactive wrapper route?
I'm just concerned about the double-bookkeeping
you'd have to write form-3 components all the way down to double-manage state for react and for the imperative/procedural graph builder API
( also in case it's not obvious, draw-board!
would use the procedural API )
hey, this is helpful, let me think for a while