Skip to content

Instantly share code, notes, and snippets.

@jhchabran
Last active February 13, 2019 12:00
Show Gist options
  • Save jhchabran/e09883c3bc1b703a224d to your computer and use it in GitHub Desktop.
Save jhchabran/e09883c3bc1b703a224d to your computer and use it in GitHub Desktop.
Google Map component, with reagent and reframe. Questions asked on Clojurians #re-frame's channel.
(defn gmap []
(let [pos (subscribe [:current-position])
gmap (atom nil)]
(reagent.ratom/run!
(when @gmap
(let [latlng (js/google.maps.LatLng. (:latitude @pos) (:longitude @pos))]
(.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 []
(let [map-canvas (.getElementById js/document "map-canvas")
map-options (clj->js {"zoom" 9})
gm (js/google.maps.Map. map-canvas map-options)]
(reset! gmap {:map gm
:marker (js/google.maps.Marker.
(clj->js {:map gm
:title "Drone"}))})))})))
@jhchabran
Copy link
Author

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
Copy link
Author

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
Copy link
Author

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
Copy link
Author

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
Copy link
Author

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

@mike-thompson-day8
Copy link

mike-thompson-day8 commented Aug 6, 2015

@jhchabran
Copy link
Author

@jhchabran
Copy link
Author

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
Copy link

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