How to build and compose reusable components in a re-frame application?

You can model events and UI using plain reagent too. That’s preferably how you should model your child components, and then wire them together at the app level using re-frame (if that’s what you’re using for state management).

Many libraries in JS land made the same mistake of coupling their functionality to Redux, because it was very popular at the time, but made it difficult to compose these components (especially in applications that didn’t want to use Redux).

Any component built with re-frame can be re-built using reagent and plain functions. Use props to pass in data / elements / event handlers / etc. and then have the component call the event handlers when necessary.

(defn contacts [{:keys [contacts on-add-contact on-remove-contact]}]
  ,,, create the UI and wire up event handlers)

;; Usage

(defn app []
  [contacts {:contacts @(rf/subscribe [:contacts/data])
             :on-add-contact #(dispatch [:contacts/add-contact %])
             :on-remove-contact #(dispatch [:contacts/remove-contact %])])

The key thing is to use components as the primary method of composition, and use re-frame to wire things up at the seams of the application. If you spread your re-frame logic across all your application, it will become less composable, less flexible. You will likely regret it later.

4 Likes