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 (props.style) 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 component's 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. :)

@martinklepsch, May 2016