Props, Children & Component Lifecycle in Reagent

Every now and then I come across the situation that I need to compare previous and next props passed to a Reagent component. Every time again I fail to find some docs and figure it out by trial and error.

Props vs. Children

In React everything passed to a component is called props. Children passed to components are passed as props.children. In Reagent things are a bit different and Reagent’s hiccup syntax doesn’t explicitly separate the two:

;; configuration and one child
[popup {:style :alert} [delete-confirmation]]
;; two children
[popup [alert-icon] [delete-confirmation]]
<Popup style="alert"><DeleteConfirmation></Popup>

In React it is well-defined where you can access the style parameter ( and how you can access the passed children (props.children).

In Reagent things are a bit different: you have a function definition which takes a number of arguments which you can just refer to in the same way you can refer to any other function parameter. This makes thinking in functions a lot easier but also overshadows some of the underlying React behaviour.

In a lifecycle handler like :component-did-update accessing component arguments via the symbol they’ve been given in the functions argument vector doesn’t work:

The moment you define components that are not simple render functions (remember those Form-2 and Form-3 components?) all updates will pass their arguments to the components render function.

The moment you render a component that has been created via reagent.core/create-class all updates will pass their arguments to the :reagent-render function, potentially triggering a re-render. The function that returned the result of create-class is only ever called once at the time of mounting the component — your top-level defn returns a component instead of being a render function itself. This is also why you need to repeat the arguments in the :reagent-render arguments.

Props in Lifecycle Handlers

Now how do we get access to these props in a lifecycle handler? The quick answer is, we use reagent.core/props — obvious, huh?

One peculiarity about the props function is that it expects the props data to be the first argument to your function. Also it has to be a map (if it’s not props returns nil).

If the first argument to your component is not a map all arguments are interpreted as children and can be retrieved via reagent.core/children.

So now we have the props for the current render, how do we access the previous ones? All previously passed arguments are passed to the lifecycle handler. Not as you might think though.

If you have a component that has a signature like this:

(defn my-comp [my-props more] …)

You can access it’s previously passed arguments like this:

:component-did-update (fn [comp [_ prev-props prev-more]] …))

comp is a reference to the current component. The second argument which is being destructured here contains what we’re looking for. As far as I understood the first item is the components constructor. The rest are the previously rendered inputs (again in React they’re all props, in Reagent they’re props and children).

As you can see you can inspect all previous arguments to a component. The way you access them differs from the default React lifecycle method signatures so hopefully this post helps to clear up some confusion about this stuff. :)

Other Posts

  1. Om/Next Reading ListNovember 2015
  2. Parameterizing ClojureScript BuildsAugust 2015
  3. ClojureBridge BerlinJuly 2015
  4. Managing Local and Project-wide Development Parameters in LeiningenJune 2015
  5. Formal Methods at AmazonApril 2015
  6. (lisp keymap)February 2015
  7. CLJSJS - Use Javascript Libraries in Clojurescript With EaseJanuary 2015
  8. Why Boot is Relevant For The Clojure EcosystemNovember 2014
  9. S3-Beam — Direct Upload to S3 with Clojure & ClojurescriptOctober 2014
  10. Patalyze — An Experiment Exploring Publicly Available Patent DataOctober 2014
  11. Running a Clojure Uberjar inside DockerSeptember 2014
  12. Using core.async and Transducers to upload files from the browser to S3September 2014
  13. Emacs & VimJuly 2014
  14. Heroku-like Deployment With Dokku And DigitalOceanMarch 2014
  15. Woodworking MasterclassesFebruary 2014
  16. Early Adopters And Inverted Social ProofFebruary 2014
  17. Living SmallFebruary 2014
  18. Sending You a TelegramJanuary 2014
  19. Running a Marathon, Or NotJanuary 2014
  20. Code SimplicityJanuary 2014
  21. What do we need to know?December 2013
  22. Sculley's DiseaseDecember 2013
  23. A Resurrection PostDecember 2013
  24. A Trip To The USSeptember 2013
  25. Analytics DataApril 2013
  26. Asynchronous CommunicationApril 2013
  27. From Zero to Marathon in Six MonthtsMarch 2013
  28. Git Information in Fish Shell’s PromptDecember 2012
  29. When We Build StuffAugust 2012
  30. Models, Operations, Views and EventsJuly 2012
  31. The Twelve Factor AppJune 2012
  32. Paris And BackMay 2012
  33. A Friend Is Looking For A Summer InternshipMay 2012
  34. Kandan Team ChatMay 2012
  35. Startups, This Is How Design WorksMarch 2012
  36. Entypo Icon SetMarch 2012
  37. Hosting A Static Site On Amazon S3February 2012
  38. Exim4 Fix Wrongly Decoded Mail SubjectJanuary 2012