This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-09-13
Channels
- # announcements (1)
- # babashka (12)
- # beginners (10)
- # biff (9)
- # calva (2)
- # cherry (21)
- # cider (14)
- # clj-commons (76)
- # clj-kondo (8)
- # clj-on-windows (34)
- # cljs-dev (5)
- # clojure (48)
- # clojure-austin (7)
- # clojure-europe (97)
- # clojure-nl (1)
- # clojure-norway (14)
- # clojure-uk (22)
- # clojurescript (137)
- # conjure (33)
- # cursive (4)
- # datalevin (1)
- # deps-new (4)
- # devcards (2)
- # duct (3)
- # events (1)
- # fulcro (12)
- # graphql (9)
- # hyperfiddle (16)
- # jobs (8)
- # kaocha (1)
- # leiningen (6)
- # lsp (39)
- # malli (38)
- # membrane (20)
- # nbb (68)
- # observability (7)
- # off-topic (49)
- # pathom (11)
- # polylith (8)
- # portal (22)
- # re-frame (6)
- # releases (1)
- # remote-jobs (2)
- # shadow-cljs (24)
- # spacemacs (2)
- # squint (6)
- # xtdb (7)
Ok, here's my take on your feed viewer. Thankfully, not too many changes. It's really useful for me to see examples because there are definitely some missing holes in the membrane docs (among other things).
> also, why do I have to wrap stuff in maps? I'm happy to provide a long answer, but the short answer is that given the requirements: • No side effects in view or event functions • Receive data only through function arguments • corollary: No hidden/local state and don't use global state Requiring a map argument seems like a small concession in order to have somewhere to shove incidental state. Basically, if you have a view like:
(defui feed-item [{:keys [feed]}]
(basic/button
{:text (:title feed)
:on-click (fn []
(println 'display (keys feed))
[[::display-feed (:uri feed)]])}))
You need somewhere to put and pass the incidental state. In the feed-item
example, that would be the button's hover state, but it could also include other incidental state like focus, text selection, cursor placement, etc.As part of that, the main changes I made to the feed example was:
(1) Change (map my-view my-view-items)
to
(for [item my-items]
(my-view {:item item}))
The reasons for this are more fiddly than I'd like and it would be great to hear if you have any feedback. Obviously, the scant documentation could be improved, but I'm also open to bigger improvements/changes.
Essentially, you run into similar trade-offs to https://reactjs.org/docs/reconciliation.html for dealing with incidental state. The defui
macro includes special handling for the for
macro, but not for map
. The idea is that if you have a feed item that lives within a nested structure, the feed view's incidental state should be linked to the identity of the particular feed item represented. As an example, the reference for a particular feed item is something like [ATOM (keypath :feeds) (nth 0) (keypath :feed)]
(2) Added a global state atom. This really isn't necessary, it's just a practice I use to make it easier to debug the UI. If something isn't working as expected, you can inspect/save the current state easily. It also makes it easier to continue with the same state after a quick fix.
(3) Made it easier to switch between skia and java2dOne other goofy thing that I should point out is:
(for [feed feeds]
(feed-item {:feed (:feed feed)}))
It's a little redundant to wrap and unwrap feed
when you already have a map with the feed key. Currently, defui
expects a literal map as the first and only argument to another defui
component.
There's no deep reason for this. It's just a missing feature of defui
that I haven't implemented yet. This should be supported in the future. I've been collecting a list of improvements for the defui
macro because I've been meaning to simplify the implementation with those updates in mind.I would have wanted to represent the feeds as a map from uri to parsed data but it felt like it didn't make sense for membrane And that's weird for me I had to change my data model to fit the UI framework
You shouldn't have to change your data model for membrane, but I can see how setting that up isn't apparent.
Here's what it looks like if you use a map of uri to data for feeds
I'm on vacation this week, but I've resolved to make some of the mentioned improvements and documentation upgrades next week.
Thank you! So what I've been missing / getting wrong was mostly the need to explicitly wrap arguments in a map for defui and how that's orthogonal to my data model
Does the example help or is there still a missing piece?
> the need to explicitly wrap arguments in a map for defui
I can't tell which aspect this is referring to:
1. the requirement for a defui component to accept a single map as an argument
2. the requirement for a component to be called with a literal map within a defui
body
Currently, the data model looks something like:
{:feeds {""
{:title "Cognitect Blog",
:description "Cognitect news, musings and more.",
:link "",
:item [{:title "Sponsoring Open Source Developers",
:description "\n <p>We a",
:pubDate "Tue, 15 Dec 2020 03:00:00 -0500",
:link "",
:guid ""}
{:title "Cognitect dev-tools",
:description "\n <p>We",
:pubDate "Thu, 20 Aug 2020 04:00:00 -0400",
:link "",
:guid ""}],
:uri ""},
""
{:title "Hacker News: Front Page",
:link " ",
:description "Hacker News RSS",
:docs " ",
:generator "hnrss v1.1-16-gb4aa33c",
:lastBuildDate "Wed, 14 Sep 2022 17:25:38 +0000",
:item [{:title "Patterns (YC S21) Is hiring devs to help us build the Figma for data",
:description "\n<p>Article",
:pubDate "Wed,14 Sep 2022 17:00:03 +0000",
:link " ",
:dc:creator "cstanley",
:comments "",
:guid ""}
{:title "DVD Bouncing Logo",
:description "\n<p>Article URL: ",
:pubDate "Wed, 14 Sep 2022 16:57:18 +0000",
:link "",
:dc:creator "mariojv",
:comments "",
:guid ""}]
,
:uri ""}}
:current-feed "",
:feed-uri "",
:membrane.component/extra {}}
I thought that's the data model you intended which implied to me that the data model is orthogonal.
I think part of the problem is that I'm too familiar with membrane and I'm also having trouble understanding what you're expecting to work that's not working.
Do you have an example of the data model you want and maybe some psuedo code that you would expect to work?Ultimately, the goal is for devs to people to write the code that fits their problem/mental model and have it "just work".
I think I see how the data model just translates, what I don't get is the need to wrap it in literal maps, it makes the defui macros feel less plastic to the data model. I would have wanted feed item to just destruct the feed map keys directly, not nav into it with a feed key
I thought I explained that here, https://clojurians.slack.com/archives/CVB8K7V50/p1663106650356379?thread_ts=1663062337.045639&cid=CVB8K7V50. Does that explain it or is there still something missing?