re-frame

repository·master·Indexed 26 days ago

https://github.com/day8/re-frame

A data-oriented, functional ClojureScript framework for building scalable Single-Page Applications. re-frame separates causal logic (events) from reactive logic (views), utilizing React/Reagent for rendering. It implements a 'six dominoes' data loop architecture consisting of event dispatch, event handling, effect handling, query, view, and DOM mutation.

Tokens
49.9K
Snippets
131
Records
275
Agent score
85%

What's inside re-frame

  1. Overview of re-frame

    master

    re-frame is a mature and stable ClojureScript framework designed for building user interfaces with a data-oriented, functional design. It focuses on high programmer productivity and scaling for large Single-Page Applications (SPAs).

    Key architectural principles:

    • Events are causal: State changes are driven by events.
    • Views are purely reactive: Unlike many React-based patterns where views are causal (using hooks or lifecycle methods), re-frame views simply react to changes in the application state.
    • React Integration: It leverages React (via Reagent) primarily as the rendering engine (the 'V' in MVC).
  2. Distinguish between Reagent and re-frame Components

    master

    In re-frame, components are categorized by how they handle their Input/Output (I/O) requirements:

    • Reagent Components (Widgets): Simple widgets representing a single value (e.g., an integer or string). They satisfy I/O requirements via positional arguments (e.g., a value and a callback-fn). They do not depend on re-frame internals.
    • re-frame Components: Larger widget complexes, often representing an entire entity. They satisfy I/O requirements using re-frame primitives: subscribe for input and dispatch for output.
  3. Understand the architectural role of re-frame vs Reagent

    master

    While Reagent provides the View (V) component of the MVC triad, it does not provide guidance for the Model (M) or Controller (C) components. As applications grow in complexity, developers face challenges regarding control logic, state management, websocket communication, and testability.

    re-frame provides a pre-defined architecture to solve these challenges, whereas using Reagent alone requires you to design and implement your own architectural solutions for state and control logic.

  4. Understanding re-frame's global registration API (`reg-*`)

    master

    re-frame uses a global registration pattern for its core APIs, such as reg-event-db and reg-sub. Instead of passing a stateful configuration object through your entire application, these functions perform side effects that mutate an internal registrar map held within re-frame.

    Why this design is used

    This approach is a conscious design trade-off: re-frame trades strict functional purity for a simpler, more ergonomic developer experience. By using global registration, the library allows you to 'build up' an app's behavior and capabilities progressively as the application boots, without the boilerplate of manual dependency injection or state passing for handlers.

    Conceptual Alignment

    From a Clojure perspective, this pattern is analogous to how defn works: it interns symbols and functions into a namespace map during program load. re-frame's registration is essentially interning an id and a handler function into its internal registrar map once, at startup.

  5. Understand re-frame's Data-Oriented Design

    master

    re-frame follows a Data-Oriented Design pattern where data is code. In this paradigm, your application's logic is driven by a Domain-Specific Language (DSL) composed of Events.

    Key concepts:

    • Events as DSL: The set of events you design for your application acts as the 'assembly language' or instruction set of your system. They model user intent (e.g., clicks, drags, keypresses).
    • Event Handlers as a Virtual Machine: The event handlers you register (using functions like reg-event-db) collectively form a 'virtual machine' that interprets and executes the event data.
    • Execution Flow: One execution context (your application code) generates the data (the events), and another context (the re-frame runtime/event handlers) executes that data as instructions.

    By designing a robust set of events, you are essentially defining the language your application speaks.

  6. Understand re-frame architecture through data flow and composition

    master

    re-frame provides system architecture by managing the interconnections between functions (referred to as 'dominoes'). Instead of focusing solely on individual functions, re-frame focuses on how data 'flows' through them via composition.

    re-frame uses different composition techniques depending on the context of the function pairs:

    1. Queue/Router: Used for initial stages of data movement.
    2. Interceptor Pipeline: Used for processing data through a sequence of steps.
    3. Signal Graph: Used for managing complex data dependencies and flows.

    Conceptually, re-frame acts as the 'transport' mechanism, similar to the water cycle, moving data through various 'forces' and phase changes within the system loop.

  7. Understand the re-frame Data Loop architecture

    master
    re-frame operates as a perpetual loop where data flows through six distinct stages, known as the 'six dominoes'. The framework manages the conveyance of data, while the developer provides pure functions to handle phase changes at various points in the loop. The core philosophy is 'derived values, flowing'.
  8. Understand the status of re-frame Enhancement Proposals (EPs)

    master

    re-frame Enhancement Proposals (EPs) follow a lifecycle to indicate their maturity and readiness for implementation or discussion. When reading EPs, check their status to understand if they are stable or experimental:

    • Placeholder: A skeleton/minimal entry.
    • Drafting: Initial writing/thinking; may be incoherent or incorrect.
    • UnderReview: Ready for general discussion in a dedicated repository Issue.
    • Accepted or Rejected: The proposal has reached a decision.
    • Released: The proposal has been implemented.
  9. Understand the re-frame Application State (app-db)

    master

    In re-frame, all application state is centralized in a single location called app-db.

    Key concepts:

    • app-db: An in-memory database (typically a Reagent atom containing a map) that serves as the single source of truth for the entire application.
    • db: Refers to the actual value (the map) currently stored inside the app-db atom.
    • Management: re-frame creates and manages the app-db for you; you do not need to declare it manually.

    Treating app-db as an in-memory database rather than just a map in an atom allows you to perform CRUD operations, queries, and atomic transactions on your application state.

  10. Understand re-frame's use of .cljc files

    master

    re-frame is implemented primarily in .cljc (Clojure Common) files rather than .cljs files. This design allows the library's tests to be executed on both the JVM and JS platforms.

    If you need to access platform-specific interop logic, refer to the following files:

    • interop.clj for JVM-specific interop.
    • interop.cljs for JS-specific interop.
  11. Understand the re-frame dynamic model

    master

    re-frame is designed around a 'simple dynamic model' to improve developer experience and reduce bugs by making the runtime easier to mentally simulate. The model is built on several core principles:

    • Discrete Time Units: The unit of time is one event. Each event is processed entirely from beginning to end before the next event in the queue begins. re-frame does not support suspended or partially processed events.
    • Transactional State Updates: When an event changes application state, it happens transactionally (instantly) in a single operation, preventing inconsistent intermediate states.
    • Single Source of Truth: State is kept in one place and updated once per event cycle, eliminating the need to synchronize distributed state across multiple stores.
    • FSM-like Event Processing: Within a single event, processing follows a linear set of logical states (often referred to as 'The Dominoes'). This behaves like a Finite State Machine (FSM) where each step is isolated and can be analyzed independently.
  12. Understand Coeffects in re-frame

    master

    In re-frame, coeffects are external inputs (like a random number, GUID, current datetime, or LocalStore data) presented to an event handler as data.

    There are two primary ways to register event handlers based on the data they need:

    1. reg-event-db: Used when the handler only needs the application state. The handler signature is (fn [db event] ...).
    2. reg-event-fx: Used when the handler needs application state PLUS other inputs (coeffects). The handler signature is (fn [cofx event] ...). In this case, cofx is a map containing a :db key (the application state) and other keys representing the injected coeffects.