Create, Read and Delete UI

Integrate Reagent and Reframe to create UI for listing and deleting graphics.

Create, read and delete UI#

With the functionality in place, we will now build the user interface for creating, reading, and deleting graphics. Here's the wireframe we started with:

Graphics Page

Title and create button#

The page title "Graphics" and the Create button can be clubbed into a component called header:

The header component renders a :div for the title and a Blueprint Button.

The call-to-action button dispatches the :a.d.f/create-graphic action, similar to what we did using the REPL. The component also subscribes to :a.d.f/creating-graphic? and uses the subscription value as :loading prop to the Button component. We have not written this subscription yet.

For this code to work, we need to require the necessary libraries:

Subscription#

We can pull the ::creating-graphic? flag from app-db using a subscription in a.d.firebase namespace. We defined this flag when we wrote the handler for ::create-graphic event:

If you find the usage of the key repetitive, you can use the reframe-utils library. It provides a wrapper to Reframe API and allows for concise event handlers, effects, and subscriptions. With reframe-utils, the above subscription can be written as:

Render header#

We can add this component to page component so it renders on /graphics route:

If everything worked well, you'll see the header component on the /graphics route. Clicking the Create New button will create a new graphic (and print to console):

Header component

Graphics list#

The job of this component is to fetch all the graphics from Firebase and display them as a grid. The graphics can be fetched by dispatching the :a.d.f/fetch-graphics event, but this is a side-effect!

The data should be fetched automatically when the component mounts. In modern React, this is achieved using the useEffect hook. In traditional React, the component-did-mount method is used to define the effects that need to be triggered when a component mounts.

To use the useEffect hook, we need to reactify Reagent components, ie convert them to React components. This means losing access to ratoms. Since Reframe's app-db is just a Reagent atom under the hood, hooks don't play well with Reframe either.

It's a common approach in the Clojure frontend community to let the router handle mount interactions. This requires the developer to use a more bare-bones routing engine so the tweaks can be made.

But since we are using React Router, we'll use Reagent's create-class method to create a class-based component. We'll then define a component-did-mount method, and dispatch the ::fetch-graphics event in that method:

Class-based components#

Unlike a functional Reagent component, a class-based Reagent component is defined by passing a map to reagent.core/create-class method. This map accepts various key value pairs like:

  • :component-did-mount (fn []) - equivalent to React's componentWillMount

  • :display-name - name of the component for debugging and logging purposes

  • :reagent-render - equivalent to React's render

A full list of accepted key-value pairs can be found in the official docs.

Graphics subscription#

We want our graphics-list component to show a loading indicator when graphics are being fetched, then render each graphic. Let's create the subscription that pulls the required data from app-db:

This will provide us with a map:

Namespaced destructuring of maps#

 

This page is a preview of Tinycanva: Clojure for React Developers

No discussions yet