re-frame

Brian Hicks 2025-11-25T11:51:51.878339Z

Hey, I have this local-first-ish app I've been working on in various iterations to learn different techniques and frontend frameworks. The basic architecture is that I store events which end up in a well-ordered series. These events then get smooshed into aggregates, event sourcing style. I'm looking into using re-frame for this, but I'm concerned that it might not be a good fit. For example, I don't want to recompute every aggregate any time a new event comes in. I also need to get the "highest" event periodically to sync, so I'm not sure I'd want to create some deeply nested structure with event subjects… but I'm not sure. Is there a way y'all would recommend approaching this? Or, am I overthinking it?

p-himik 2025-11-25T13:08:25.103369Z

Your concerns don't sound related to re-frame itself. > I don't want to recompute every aggregate any time a new event comes in. That's a concern for every event-sourcing system out there, and they all (well, I assume) do some kind of caching, which you can also do with re-frame. Of course, it has to be done in a way where you don't just invalidate the whole cache when a new event comes in - you just update the cache with that event. > I also need to get the "highest" event periodically to sync Sounds like a simple peek on a vector of events. Or, if you need multiple events, a subv. Or am I oversimplifying it? Not sure where a deeply nested structure would come from.

Brian Hicks 2025-11-25T13:17:10.109359Z

hmm, maybe I need to be more specific… I think in this case, I'd have a list of events in my app database, right? Then I'd have a level 2 query thing that groups the events into subjects, and a level 3 query thing that computes the aggregates. Hypothetically that would mean every level 2 function being reevaluated whenever a new event comes in, right? But I'd kinda like it to be the case that they only get the diff.

Brian Hicks 2025-11-25T13:17:34.623729Z

I agree with your point about the caching. I just don't know how to accomplish that.

Tom H. 2025-11-25T13:18:33.212179Z

Are these events related to front-end state or more like business-logic? You could potentially use an independent implementation of event sourcing that updates the ui via re-frame once it's computed the current state.

Brian Hicks 2025-11-25T13:20:08.667759Z

I want to make sure I answer that properly, so I'm gonna rephrase: the events are things that would be stored in a database, not stuff like which dropdown is open. I think that falls under business logic in your categorization?

Tom H. 2025-11-25T13:21:05.008689Z

Yeah for sure

Brian Hicks 2025-11-25T13:23:17.476609Z

to be honest with you, I'm barely getting to grips with re-frame's design (although I've worked a lot with Elm in the past, which means I'm comfortable with the really high-level similarities.) would you be willing to share more about how you'd approach that?

Brian Hicks 2025-11-25T13:24:08.849829Z

I hope I'm not trying to force re-frame into a place it isn't designed. Trying to learn it, though, as I just accepted a new job where they're using it and I want to get up to speed. 😅

Tom H. 2025-11-25T13:36:44.231649Z

I think there are a lot of ways to structure things and there's no right way but I've had the most success when I try to decouple business logic/state and UI logic/state. In practise that might be something like: • The app receives a new "business event" (or initial state) and using non-reframe system calculates the current "business state" and saves it to a single key-value in the re-frame db • re-frame subscriptions depend on that "business state" value (and other UI-specific entries in the re-frame db) to determine the UI state • taking an action in the UI dispatches a re-frame event, which may also then create new "business events" in your event-sourcing model, which start the loop again

Tom H. 2025-11-25T13:41:45.540119Z

I think it is also common to leverage the event/subscription system for business logic and I think some of the things in re-frame alpha make that cleaner https://day8.github.io/re-frame/FAQs/alpha/

p-himik 2025-11-25T13:50:39.525369Z

"Business logic/state" is a bit overloaded term so I myself would avoid it in cases where subtle differences might matter as it's never clear whether people are talking about the same thing. I much prefer "app state", with a clarification that it's what re-frame is concerned about. In other words, data that is needed to make an app that satisfies all the requirements. Data that can be saved somewhere in a file, restored from a clean slate, and that would create the same exact UI and UX as before. From that perspective, where does a collection of events stand? Does your app care about every single event, including the very first one, for infinite time? Or does it care only about some base state + new events? If it's the latter, does it care about the base state in the "as received on page load" sense or in the "as the last saved state" sense?

Tom H. 2025-11-25T14:14:00.378159Z

I suppose I consider "app state" the combination of "UI-only state" + "business state" and that it can be useful to consider the two independently. I don't love the names though.. (maybe "domain state"?)

Kimo 2025-11-25T14:16:52.840879Z

> I don't want to recompute every aggregate any time a new event comes in. I think re-frame.flow could work for this. You define a predicate function which checks the app state on every event to decide whether to recalculate.

Tom H. 2025-11-25T14:20:20.811129Z

https://day8.github.io/re-frame/Flows/

✅ 1
Brian Hicks 2025-11-25T14:47:23.749419Z

I’ll have a look at Flow, thanks. As to what I care about: this is an app that tags points in time with data. You can think of it like a time tracker, and it’s close, but not exactly like something you’d use for a timesheet. So I define “questions” as a title and what kind of data it collects (numeric or string). I want to get all the edit events for all the questions right away. Then the “pings” are just points in time with collected data. Those I want to only get a range in time, say 30 days. In the past, I have stored this data in IndexedDB and pulled it into memory when the app loads. That might be fine here, especially since it looks like I can do whatever integration I like with effect handlers. I suspect it would be best to group events by their question or ping. Then those can be extracted and aggregated.

Kimo 2025-11-25T18:47:49.503189Z

Feel free to DM me if you'd like a second pair of eyes on your codebase

❤️ 1
Leonard Kuehlke 2025-11-25T14:27:36.323489Z

TodoMVC/Secratary not compatible with newest cljs. Hey I was just going through the re-frame docs and as recommended I was about to go through the todomvc example. However the current version fails with the following runtime error: TypeError: goog.reflect.cache is not a function fromInt integer.js:95 Seems that the secretary dependency is responsible for this. Secretary seems to fail for the current cljs version. As a quick fix pinning cljs explicitly too 1.11.60 did the trick for me. Maybe someone else finds this helpful. Should I open an issue for this? I guess this is really a secretary issue in origin but since todomvc is a very nice example its a shame that it currently does not run out of the box.

Kimo 2025-11-25T14:28:46.782849Z

Yeah, please make an issue. That demo can probably be clearer if we remove secretary.

Leonard Kuehlke 2025-11-25T14:32:05.993939Z

Alright. I will do so. The docs are very good by the way. I am enjoying re-frame a lot.

Kimo 2025-11-25T14:44:44.477839Z

The docs are more important than the code, haha

Leonard Kuehlke 2025-11-25T14:47:18.337069Z

Yeah kinda 😄.