Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Google Map component, with reagent and reframe. Questions asked on Clojurians #re-frame's channel.
; Following code is WRONG, see comments for details.
(defn google-map []
(let [pos (subscribe [:current-position])]
(reagent/create-class
{:reagent-render
(fn []
[:div
[:h4 "Map"]
[:div#map-canvas {:style {:height "400px"}}]])
:component-did-mount
(fn []
(let [map-canvas (.getElementById js/document "map-canvas")
map-options (clj->js {"zoom" 9})
gmap (js/google.maps.Map. map-canvas map-options)
marker (js/google.maps.Marker. (clj->js {:map gmap :title "Drone"}))]
(reagent.ratom/run!
(let [latlng (js/google.maps.LatLng. (:latitude @pos) (:longitude @pos))]
(.setPosition marker latlng)
(.panTo gmap latlng)))))})))
; Another attempt, using props and lifecycle to udpate marker position
(defn gmap-component []
(let [gmap (atom nil)
options (clj->js {"zoom" 9})
update (fn [comp]
(let [{:keys [latitude longitude]} (reagent/props comp)
latlng (js/google.maps.LatLng. latitude longitude)]
(.setPosition (:marker @gmap) latlng)
(.panTo (:map @gmap) latlng)))]
(reagent/create-class
{:reagent-render (fn []
[:div
[:h4 "Map"]
[:div#map-canvas {:style {:height "400px"}}]])
:component-did-mount (fn [comp]
(let [canvas (.getElementById js/document "map-canvas")
gm (js/google.maps.Map. canvas options)
marker (js/google.maps.Marker. (clj->js {:map gm :title "Drone"}))]
(reset! gmap {:map gm :marker marker}))
(update comp))
:component-did-update update
:display-name "gmap-component"})))
(defn gmap-wrapper []
(let [pos (subscribe [:current-position])]
(fn []
[gmap-component @pos])))
@jhchabran

This comment has been minimized.

Copy link
Owner Author

@jhchabran jhchabran commented Aug 4, 2015

While it's working (at least appears to be, I get my map panning properly according to gps position), I'm asking myself the following questions : ( 1 being the one I'm the most unsure of, to 4 being where I think I got it right).

  1. about reagent.ratom/run!, isn't it a clear violation of one the re-frame's principles, which states, do not use reaction in views ? (run! being, as far as I understand, a reaction that runs itself initially whereas reaction requires to be deref'ed to be executed, but in this case, it doesn't hold any meaningful value)
  2. directly calling .setPosition in the :reagent-render function works but it felt wrong because the markup once rendered doesn't change at all.
  3. let inside a let let but while being usually a hint of something done wrong, putting latlng there doesn't work because it's not dereferenced in the render function, so it seems fine to me.
  4. storing the google map instance in app-db feels wrong to me, I thought it's more something related to the component that the app state itself. Still I need to hold a reference to it to be able to update the map according to app-db, so a local atom felt right. see previous revision Just added it to the let block as the run! is now called inside :component-did-mount.
@jhchabran

This comment has been minimized.

Copy link
Owner Author

@jhchabran jhchabran commented Aug 5, 2015

So far and according the feedback I got, 2 and 3 are correct. 4is probably correct anyway. Still waiting for some validations on 1 :)

@jhchabran

This comment has been minimized.

Copy link
Owner Author

@jhchabran jhchabran commented Aug 5, 2015

I feel like if's correct enough it would be a nice addition to https://github.com/reagent-project/reagent-cookbook/tree/master/recipes/google-maps given the re-frame part is replaced with a ratom.

@jhchabran

This comment has been minimized.

Copy link
Owner Author

@jhchabran jhchabran commented Aug 5, 2015

4 was just a consequence of putting the run! at the wrong place, initial comment updated accordingly.
I don't think it was wrong per se but it's now unnecessary once run! is called where it should be.

@jhchabran

This comment has been minimized.

Copy link
Owner Author

@jhchabran jhchabran commented Aug 5, 2015

⚠️ Got some feedback from Re-Frame's author, using run! is very wrong here (if following re-frame approach).

@mike-thompson-day8

This comment has been minimized.

Copy link

@mike-thompson-day8 mike-thompson-day8 commented Aug 6, 2015

@jhchabran

This comment has been minimized.

Copy link
Owner Author

@jhchabran jhchabran commented Aug 17, 2015

@jhchabran

This comment has been minimized.

Copy link
Owner Author

@jhchabran jhchabran commented Sep 9, 2015

It should use will-receive-props for update as we don't interact with the dom as opposed to http://nils-blum-oeste.net/clojurescripts-reagent-using-props-in-lifecycle-hooks/ example.

@raymcdermott

This comment has been minimized.

Copy link

@raymcdermott raymcdermott commented Feb 13, 2019

When using this I have found it important to run :component-will-unmount to dispose of the stateful component

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment