This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-01-15
Channels
- # aws-lambda (3)
- # beginners (17)
- # boot (65)
- # cider (3)
- # cljs-dev (7)
- # cljsrn (82)
- # clojure (82)
- # clojure-italy (1)
- # clojure-russia (25)
- # clojure-spec (56)
- # clojure-uk (5)
- # clojurescript (52)
- # css (2)
- # datomic (6)
- # emacs (1)
- # hoplon (9)
- # jobs-discuss (5)
- # leiningen (8)
- # mount (2)
- # nginx (1)
- # off-topic (2)
- # om (1)
- # om-next (9)
- # perun (13)
- # portland-or (1)
- # re-frame (13)
- # reagent (20)
- # remote-jobs (2)
- # ring (5)
- # spacemacs (1)
- # specter (10)
- # untangled (5)
- # yada (6)
How would someone know if it's :rowHasChanged
or :row-has-changed
?
except of course looking at someone else's project everytime you wonder what's the right keyword
@ejelome unless thereโs some special rule, it should be camelCase. so :rowHasChanged
.
So having spent an hour or so re-acquainting myself with Re-frame albeit on React Native, I'm suprised how familiar it feels. I'd not done any re-frame stuff for maybe a year but I'm immediately jumping into adding subs etc. Thank you to all that helped this project and it's dependencies to where they are now. Really impressive.
@ejelome reagent automatically converts kebab-case to camelCase
@ejelome what's your question about list-views?
Saying that, one thing that I'm not familiar with is how to persist the app-db so it survives application restarts. Is there a pattern for this or documentation that I'm falling to find on this subject?
mostly it doesn't matter, correct
I mean for props
for nested maps passed to components, perhaps it does matter
I see, thanks, yeah, I'm confused with props, some examples uses kebab, others use camel case, and I don't even know how people know the right casing for each props
if you share what you have w/r/t a list-view, I can see if I can spot an issue
it is confusing: HTML has kebab-case, JSX uses camelCase, Reagent goes back to kebab-case ๐
XD correct, that's really confusing until you said it auto converts to camel case anyway, thanks!
All this talk of kebabs is getting me hungry...
@paulspencerwilliams you can persist in LocalStorage
or on the server, if you keep a session
pretty much same as on the web
@ejelome we should start a cljsrn cookbook with examples for people so it's easier to get started
ListViews are kind of a pain in the ass if you want to use section headers. Hereโs a helper function I wrote to make generating the DataSource easier.
(defn gen-cloneWithRowsAndSections-args
"
INPUT:
section-v-m = [{:id 2 :name \"Group 1\"} {:id 3 :name \"Group 2\"}]
row-v-m = [{:id 5 :firstName \"Althea\"} {:id 6 :firstName \"Alycia\"}]
section-id->row-ids = {2 #{5} 3 #{6}}
section-id-key = :id
row-id-key = :id
OUTPUT:
{:section-ids [2 3]
:row-ids [[5] [6]]
:data-blob {2 {:id 2, :name \"Group 1\"}
3 {:id 3, :name \"Group 2\"}
5 {:id 5, :firstName \"Althea\"}
6 {:id 6, :firstName \"Alycia\"}}}
"
[section-v-m row-v-m section-id->row-ids section-id-key row-id-key]
(trace [section-v-m row-v-m section-id->row-ids section-id-key row-id-key])
(if (empty? row-v-m)
{:section-ids []
:row-ids []
:data-blob {}}
(let [sorted-data-ids (mapv row-id-key row-v-m)
section-and-row-ids (reduce (fn [accum svm]
(let [section-id (get svm section-id-key)
filter-pred (get section-id->row-ids section-id #{})
row-ids (filterv filter-pred sorted-data-ids)]
(-> accum
(update :section-ids conj section-id)
(update :row-ids conj row-ids)
(update :data-blob assoc section-id svm))))
{:section-ids []
:row-ids []
:data-blob {}}
section-v-m)
convert-data-to-map (reduce (fn [accum m]
(let [k (get m row-id-key)]
(assert (not (nil? k)))
(assoc accum k m)))
{} row-v-m)
merge-in-data-map (update section-and-row-ids :data-blob merge convert-data-to-map)]
merge-in-data-map)))
yeah, that'd be highly appreciated I'm still on the stage where trying to connect components to project ๐
right, I think this is the most painful from the components so far, the ListView, bec. you have to juggle with datasource, clonewithrows, and a function just to display each row, here's my attempt for 1:1 from the react native basics for listview, it's an error of course XD
(ns using-alist-view.android.core
(:require [reagent.core :as r]))
(def ReactNative (js/require "react-native"))
(def app-registry (.-AppRegistry ReactNative))
(def list-view (r/adapt-react-class (.-ListView ReactNative)))
(def data-source (r/adapt-react-class (.-DataSource (.-ListView ReactNative))))
(def text (r/adapt-react-class (.-Text ReactNative)))
(def view (r/adapt-react-class (.-View ReactNative)))
(def ds (new data-source {:row-has-changed #(not= %1 %2)}))
(defn list-view-basics []
[view {:style {:flex 1 :padding-top 22}}
[list-view {:data-source (.cloneWithRows ds ["John", "Joel", "James", "Jimmy", "Jackson", "Jillian", "Julie", "Devin"])
:render-row #([text %])}]])
(defn app-root []
[list-view-basics])
(defn init []
(.registerComponent app-registry "UsingAListView" #(r/reactify-component app-root)))
Yeah. The ListView component was definitely designed for an imperative nested-for-loop style. Makes no sense from a pure data standpoint.
@pesterhazy aparently AyncStorage should be used instead of LocalStorage
right that's what I meant @paulspencerwilliams
And I recommend using react-native-storage
if you are using it for caching. Setting a default expiration date saved me a bunch of time. Also the remote sync is interesting.
https://github.com/sunnylqm/react-native-storage
@ejelome I think you're missing a #js
: (list-data-source. #js {:rowHasChanged not=})
(def ds (data-source. #js {:row-has-changed #(not= %1 %2)}))
here's a wrapper component that abstracts away the "data-source" nonsense: https://gist.github.com/pesterhazy/f6e6fca0c663a5e6bcc21a09b8b01747
(def data-source (.-DataSource (.-ListView ReactNative)))
check my gist ๐
yeah, @pesterhazyโs version is good
Oh thatโs interesting. Hadnโt heard of react-native-sglistview
before.
the sg-list-view example is very good, but I'm getting an error on the data-source part:
{:data-source (.cloneWithRows ds (clj->js ["John" "Joel" "James" "Jimmy" "Jackson" "Jillian" "Julie" "Devin"]))}
it finally worked, thanks @pesterhazy ๐
but curious, why is {:rowHasChanged not=}
and {:rowHasChanged #(not= %1 %2)}
seems to have similar effect?
They should be identical
yeah javascript (and clojurescript) doesn't care about arities
cljs.user=> ((fn [x y] [x y]) :a)
[:a nil]
cljs.user=> ((fn [x] [x]) :a :b)
[:a]
It's a very ... permissive culture ๐
ahhh, I've got used to explicitness so that somewhat confused me, so it's all really just because of how js deal with parameters
would it be ok if I put numerous questions, I will outline them here so that other newbies can all get a brief summary they might also encounter
Here: ๐ What's the difference between (first one doesn't work, but the other does work):
(r/adapt-react-class (.-DataSource (.-ListView ReactNative)))
;; vs.
(.-DataSource (.-ListView ReactNative)))
`
Why do I have to use #js
, e.g.:
(data-source. #js {:rowHasChanged #(not= %1 %2)})
`
Why do I have to use clj->js
, e.g.:
{:dataSource (.cloneWithRows ds (clj->js ["John", "Joel", "James", "Jimmy", "Jackson", "Jillian", "Julie", "Devin"]))}
And why /as-element
was even necessary for the render, e.g.:
:render-row #(r/as-element [text %])
`ad 1) "ListView" is a React component. To use it in reagent, you need to "adapt" it into a Reagent component.
DataSource, on the other hand, is just a JavaScript class (the .
means instantiation), so no adaptation necessary.
ad 2) you're passing a value to the DataSource constructor. {:a :b}
is a PersistentHashMap, which a JavaScript lib won't understand. So you need to create a JavaScript object. #js
is a literal to do that. (js-obj :a :b :c :d)
is more explicit.
ad 3, same issue. []
creates a PersistentVector, which is not a js array. clj->js
is one way to do that, better ways would be into-array
or #js ["john" ...]
ad 4, as-element is necessary for the inverse reason why adapt-react-class exists. render-row expects a React render fn, i.e. a fn that returns a React element (in JS usually generated through JSX)
if you just returned [text "asdf"]
, that would be a PersistentVector, which JS has no clue about
makes sense?
btw these are all reagent or js interop issues, nothing particularly to do with react-native
(although I realize react-native shows these issues more than react-web)
ahhh, so in ... 1) it's component (r/react-adapt-class) vs. js class (.-JSClass) 2) and 3) are merely because for converting cljs data to js objects so JS can understand them and 4) is for returning a component so you need to wrap it like with as-element
thanks @pesterhazy, awesome answers! ๐
exactly
I wanted to blog about this for a long time, I think I'll do that soon
I thought all this time that [text "asdf"]
is already returning a component, never knew it's still a PersistentVector
will publish it on https://presumably.de
Regarding using asyncstorage or react-native-state to push app_db to long term storage.. Any common patterns for doing so? Ideally it would only need to be pushed on app close, and read on app initiation, but the pessimist in me thinks it might have to happen when an action updates the app_db incase battery dies etc? If this is that case, then could / should the events just write to it and not to app_db, and subs read from it. Otherwise, what's the benefit of having 2 copies around? Obviously, not using app_db is far from idiomatic when using re-frame. Feels like I'm missing something...
Maybe this question would be best placed in #re-frame