This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-05-17
Channels
- # announcements (10)
- # aws (10)
- # babashka (11)
- # beginners (77)
- # calva (9)
- # cider (10)
- # cljdoc (7)
- # cljs-dev (47)
- # clojure (47)
- # clojure-uk (4)
- # clojurescript (87)
- # community-development (15)
- # conjure (14)
- # core-async (25)
- # cursive (6)
- # fulcro (6)
- # helix (3)
- # joker (2)
- # nrepl (1)
- # off-topic (1)
- # pathom (9)
- # pedestal (6)
- # re-frame (22)
- # reitit (15)
- # shadow-cljs (26)
- # spacemacs (16)
- # testing (2)
- # tools-deps (12)
- # uncomplicate (10)
- # xtdb (22)
Anyone familiar with the new CLJS webpack bundling and exports? I'm trying to get a reagent component to render via storybook - it works with some caveats. I'd like to better understand how it should work and what the limitations are.
Here's my code based on the new webpack guide. https://github.com/olivergeorge/webpack-repros/tree/storybook-vs-reagent
Questions...
1. in stories/2-SimpleComponent.stories.js
is it sensible to import '../out/index.js';
?
2. it doesn't work for -O none
until i setup out to be staticly served. Is there an alternative where the webpack bundler handles that. I'm imagining some additional imports before my core namespace. (replacing the network requests). The other issue here is the delay loading the namespace causes my code a race condition.
3. is there a more correct way to access my code via a javascript style "export default ..." type statement in my code? Currently I'm accessing via a ^:export
so, I have a question everyone will love. I googled around before asking and found this: https://github.com/athomasoriginal/clojurescript-30/tree/master/07-array-cardio-2 And I saw it elsewhere too, that the standard answer is to convert the data to hash-map, which is find if you want to read the value. But what if I have to update it? Should automatically change everything into a custom datastructure setup for the sake of accomodating the language?
Because this is basically about what I send to back to the server, if there is an "id" key that's not nil, then I have to http PUT instead of http POST, and change (or replace, performance is not an issue here)
I’m not sure what the question is? Transforming native JS values to Clojure data structures?
agreed. I see a "standard answer" but have no idea what the question is nor what the link is supposed to demonstrate
if you have [A1, A2, A3, .... , An] where A is a large object each with an id
property, I give you id
and a list of keys for something like assoc-in or update-in, and a value to update the map with the id at that key (branch?), what do you use?
Apart from reduce, because with reduce everything is possible, I know it it's like using a while or a for loop
There's now https://github.com/mfikes/cljs-bean, if you're talking about the interop
> convert the data to hash-map, which is find if you want to read the value. But what if I have to update it? Yup, I guess I assumed that non-hashmaps would be JS objects in a JS array
@ashnur i’m not sure what you have against reduce; it is perfect for these sort of corner cases / bulk operations. what you basically want is to find, in an unordered list, the map with a specific id and then update that map. the core library doesn’t provide an exact tool for this, but you can easily write your own using reduce
or for
.
you could even give it a name, update-when
:
(update-when #(= (:id %) 2) assoc :foo "bar")
There’s nothing Clojure specific here. You have a bunch of random stuff in a container, without an index you have to walk the container and find the one you care about.
of course there is, it's specific to clojure that this is hard to do, when everything else is easy
or, if you know you want to do lots of updates, and not have to walk the container sequentially for each update, then use a hash-map or similar thing that lets you find elements by their id much more quickly than linear scan.
for you, I repeat : ), I need to update this data and I need to send it to a backend server, it's not a question of how to represent something, otherwise I would be using something that's better already and I wouldn't be in this position in the first place
@ashnur There are some libs specialized in these query like things when you don't want to write your own reduce. The best one I know which allows write queries as well is Spectre
Also in your case, it sounds like a use case for map or for. Since you don't intend to grow or shrink the input collection. You only want to possibly modify each element in the collection
@didibus I do intend to both grow and shrink the collection, just not during this operation. But again, it's more about trade-offs. I can either convert it to a hashmap so it's easy but then I have to convert it back to a vector later, or I can write some complicated helper function to use which then leads to incidental complexity. I can not be as casual about this as some of the responders seem to expect me to be : )
Also, if you have a vector, and want to use named keys, it's possible to do something like:
(def person ["John" 13 "4.2"])
(let [name #(get % 0)
age #(get % 1)
height #(get % 2)]
(name person))
This gives the idea. But you can create named getters for the elements. So you have a nice mapping between name and a better that can extract the right position out.You can make yourself setters as well:
(defn make-person
[name age height]
[name age height])
(defn get-name
[person]
(get person 0))
(defn set-name
[person name]
(assoc person 0 name))
You can also just map names to index like:
(def name-idx 0)
(def age-idx 1)
(get person age-idx)
(assoc person name-idx "Bob")
the goal is to have a vector of hashmaps, one of them updated, but technically I don't have to store the data in that format, I could just serialize to it at the end before I send it over the wire
@ashnur why do you dismiss reduce when it is a good solution? reduce-kv would be even better, probably best performance wise
I don't necessarily, I just want to be absolutely sure I don't start using it indiscriminately, mostly because with reduce I can do everything, I used a lot in js, and I don't want to keep js habits for cljs code
why not? reduce is a good thing, I use it everywhere. probably one of the most fundamental functional things. every functional lang has it, often called fold though
So why not:
(def updates
{:123 {:keys [:a :b :c]
:val 25})
(mapv
(fn[a]
(let [transform (get updates (:id a)
type (:type transform)
keys (:keys transform)
val (:val transform)]
(if transform
(assoc-in a keys val)
a
vec-of-a)
it's more about the js habits than reduce. If there is a good solution that is special to cljs, I will never see it because I already wrote some spaghetti code for that
Ya, with regards to that I'd say Specter is one common approach, needed when you have powerful requirements. Otherwise, it is often possible to compose transducers or sequence functions in order to achieve a particular looping behavior without resorting to a loop. That said, it's not always possible, and sometimes you need to resort to a loop. Map and reduce are halfway between a loop and higher level sequence functions though. So still better then a full on loop/recur. And a recursive loop is also better then an imperative mutable loop. So there's a big spectrum here.
I used the indexOf trick (update-in state-map [:vector-data (first (keep-indexed #(when (= (.id %2) curr-id) %1) vector))] value
because I remember watching on youtube, and it's like lenses or similar, "now I have 2 problems"
Its not like lenses, it is on functionality, but it uses a different approach. Personally I find Specter easier to use then lenses.
Specter would be good if you needed to do a lot of really nested queries of big data-structures with ton of nested stuff, and you need to query or update certain parts
The downside in ClojureScript is one more thing to bundle with your app, increases bundle size
Also, just one last thing, converting data structure from one another is pretty idiomatic. So like, convert to a more natural structure for transforming, and then convert back. Unless you start seeing performance issues around it (rare), it's totally fine to do that and helps having cleaner code a lot.
turning this into a map first is completely wasteful. don't do that if you only do a single update
And in fact, converting to more appropriate data-structures and back can sometimes help performance even, if it becomes a more optimal structure for the following manipulation
You can also use get and assoc and update on vectors by the way. Vectors are indexed too, just by integer instead of key.
didibus, that's what I was doing, but update-in requires .indexOf or .findIndex, that's where I stopped reading the docs and came here to ask my questions : )
Hum... Maybe that's some ClojureScript specific thing. I'm more of a Clojure dev so never heard of this
so, I started thinking about how I would have to do this with reduce-kv, and it's weird because I have to do 2 things, until I find my target, I need to conj I think? And then update the value, then conj both the value and the rest of the vector wrapped in a reduced call?
(defn merge-for-id [the-vec the-id m]
(reduce-kv
(fn [the-vec idx {:keys [id] :as v}]
(if-not (= id the-id)
the-vec
(-> the-vec
(update idx merge m)
(reduced))))
the-vec
the-vec))
(merge-for-id data 123 {:new "value"})
this is what I mean, all kinds of incidental complexity pops up, I am sure this is very simple code for clojure/script devs, but for me it seems weird that the language that says that if I adopt it, my life will be easier because I can use core functions for everything, can't do something admittedly trivial without a couple of custom functions
so you expect core to solve every possible problem for you? I don't know a single language where that would be the case. I can think of at least 10 different ways of solving this particular problem, each with its own trade-offs so you are going to have one the works best for you and your use-case. that is not something core could possibly ever do.
no, not every single problem, why are you saying something outrageous like that? I clearly specified that my expectations were about something "admittedly trivial", which is under no circumstances "every single problem".
this is not a "admittedly trivial" problem as you make it out to be. what if you have multiple matches in a vector? what if you vector has a million elements? what if it has 5? what if you don't need to check the key via =
but use some other predicate? what if you want to batch updates to avoid traversing the entire vector multiple times?
specter
is a good example of a library that tries to solve these kinds of things in a more generic way but you have to pay for it in code-size ... again a trade off that doesn't make sense for all apps
if you are going to update things often by id it makes sense to have a structure of {id {:id ... :key "val" ...}}
to begin with. if you care more about the ordering and rarely update by id then a vector is better suited
let's not argue about definitions, someone else said the problem seemed trivial, I believed them, if you say it isn't, I can believe you too
that's what I started with though, it's like people only react to half of what I write : )
I did ask my question in the beginning, should I convert everything or should I write helper functions
because I have to produce a vector of hash-maps but I can see it's not the best way to deal with them.
In fact, the actual JSON I have to send is
{rootkey: { stuff: 'whatever', someVector : [ { somekey: "with values", actualVectorIamAskingAbout: [ {id: 1, nested: data}, {id:2 nested: data2 } ] } ] } }
we do not know enough about the problem you are trying to solve. the answer whether you should convert or not depends on your requirements and code. if you have a million items in the vector and want to update one element turning it into a map first is extremely wasteful.
that's understandable, I don't expect people here to ship my solutions. And if I ask a bad question, I can face this fact : )
it's a small vector, technically the whole structure is a waste of time and space. With some refactoring it would be actually trivial to deal with it, but this api is some kind of demonic device, it's like someone decided to implement a custom rpc over django rest framework
note that this only works if you are sure you have a vector, it will break if its not a vector
Anyone can suggest a good succinct tutorial for CSS geared at experienced developers?
And maybe with resources in this format to describe the features: https://yoksel.github.io/flex-cheatsheet/ I found this explained flexbox really well
http://css-tricks.com have good entries for any topic