Introduction

This book demonstrates how to use the tools Fulcro offers to solve various real-life problems, with realistic examples.

Warning
This is just a very early draft

Content proposal

The book is structured into sections focused on a particular problem / tool.

Sections:

  1. Pushing side-effects to the transaction subsystem and remotes

  2. Repeating elements and recursive queries

  3. JS interop - leverage existing JS libraries

  4. …​ (more to come)

Example ideas

  1. SortableList

  2. leverage the statecharts in the cookbook - perhaps a simplified sign-up/login/resume session example

  3. A custom remote to offload heavy work to a WebWorker

1. Pushing side-effects to the transaction subsystem and remotes

1.1. Introduction

In Fulcro, we want rendering to be as pure a function of data as possible. Yet, any application needs to perform side-effects to be useful. Fulcro’s answer to that are mutations, which are submitted to the transaction subsystem and executed asynchronously by a remote. The remote essentially everybody is using is Pathom, whether running on the server-side or in the browser itself, as an adapter for remote REST APIs. But it doesn’t need to be the only remote. If you need to talk to an endpoint directly, use the browser’s local storage or IndexedDB, or to offload an expensive computation to a WebWorker, a custom remote - which is just a simple function - is your solution.

Remotes and the transaction subsystem provide good functionality out of the box:

  1. Responses can be automatically normalized and merged into the client DB (see m/returning & friends)

  2. Possibility to cancel running requests (as long as the remote supports it)

  3. Error handling

  4. Status tracking (loading/failed/success)

  5. Progress tracking (as long as the remote supports it)

Writing your own remote implementation is simple - it is just a map that contains a :transmit! key whose value is a (fn [remote send-node] ). You’d like need to write a tiny adapter layer to process the …​tx-processing/ast, which is the parsed EQL query, and to return an appropriate tree of data.

1.2. Recipes

WebWorkerRemote: Offloading an expensive calculation to a WebWorker

TODO

2. Repeating elements and recursive queries

2.1. Introduction

Sometimes we run into recursive use cases, where a component contains itself, for example when representing a file system, where folders can contain other folders. A more troublesome case is when we have multiple components that mutually include each other.

You have essentially three ways to approach this problem:

(1) Simplify your UI so that you have a single component including itself. Then you can use EQL’s bound or unbound Recursive Queries with a join on itself, represented by a number for the desired number or levels or the symbol …​. Ex.: [{:folder/subfolders '…​}] (or, if you want to only load e.g. a single level at a time, [{:folder/subfolders 1}]).

(2) "Unroll" the recursion by defining a unique component for each level, such as Folder1, Folder2, Folder3 and leveraging the power of Clojure to avoid code duplication.

(3) An ad-hoc solution for a rare case (see e.g. the Solving mutually recursive elements recipe)