10

I am doing an Ajax GET from my Reagent application, to load some stuff from the database.

I am not entirely sure what is the best way of getting the result of such ajax call to my page, considering that if I put it in an atom, then Reagent automatically re-renders a component when an atom is dereferenced, which means I get an infinite sequence of ajax calls.

For some code,

(def matches (atom nil))

(defn render-matches [ms]
  (reset! matches (into [:ul] (map (fn [m] ^{:key m}[:li m])
                                   (walk/keywordize-keys (t/read (t/reader :json) ms)))))

This function basically creates a [:ul [:li "Stuff here"] [:li "And here"]]

Which i would like displayed on my page, which now has the following code.

(defn standings-page []
  (GET "/list-matches"
       {:handler render-matches})
  @matches)
Helios
  • 457
  • 6
  • 17
  • How does the `GET` request get triggered? On page load? Or only if you need that reagent component? Or user action? You're complecting a lot of stuff here. I'd only put the data (not hiccup) into the atom and render the list in `standings-page`. If you need to only request it once you might check out `delay` and reference the delay in `standings-page`. But again, that depends on your use case (hence the first few questions) – ClojureMostly May 06 '15 at 12:21
  • Yeah, don't ever call side-effecting code directly from render. Either do it from a lifecycle functin (like will-mount or did-mount) or in the reagent component init (as shown in Michiel Borkent's answer). –  May 12 '15 at 14:25

1 Answers1

12

I think it's better to save only data in an atom and to generate the HTML as part of the component logic.

Also it's better to trigger the AJAX call outside the render phase, for example, before the component will mount, or as the result of an event (on-click on a button for example).

Like this:

(def matches (atom nil))
(defn component []
  (let [get-stuff (fn [] (GET "/..." :handler (fn [response] 
                           (reset! matches (:body response))))]
    (get-stuff) <-- called before component mount
    (fn []
      [:ul
        (for [m match]
          ^{:key ...} 
          [:li ...])])))

This is called form-2 in this post.

Michiel Borkent
  • 34,228
  • 15
  • 86
  • 149
  • 1
    Thanks Michiel. Your comment was very helpful and I understood the logic a bit better :) See you around at a Meetup! – Helios May 30 '15 at 15:06
  • 1
    Isn't the key to form-2 the fact that you return a function? If so, why is it necessary to use `let`? Couldn't you do the following: (def matches (atom nil) (defn component [] (GET "/..." :handler (fn [response] (reset! matches (:body response)))) (fn [] [:ul (for [m match] ^{:key ...} [:li ...])])) – DandyDev Jan 09 '16 at 21:04
  • @DandyDev You can. I just created the name to express the intent, but you can do without the function. – Michiel Borkent Jan 09 '16 at 21:06