fulcro

Declan 2026-04-13T16:03:03.533529Z

I have a question / observation about dynamic routers and how they can be influenced by setting :initial-state on target components I'm able to reproduce some behaviour and I don't know if this is what I should be expecting, if this behaviour is "correct" or not.. I have a Fulcro app that is using dynamic routers to switch to different components when a user navigates to different urls This app is using REST calls to communicate with a server and stores the responses in app state The data from the server is organised in app state using specific components e.g. DataResponse The scenario is a user requests an action on a page e.g. "/load" which fetches data from the server They then navigate to a different page e.g. "/detail/2" There is a component which acts as the "base" of "/detail/2" e.g. DetailPage This is the component which is loaded by the dynamic router in a call to "add-route-target!" The :query of "DetailPage" includes a reference to the component DataResponse which is the edge where the data can be found :detailpage/data (comp/get-query datans/DataResponse) What I am expecting is that as the DetailPage component is loaded, the query normalises the response into the component so that the data can be found in :detailpage/data What I find is that this all works, only if the form of :initial-state for DetailPage is an empty map e.g. :initial-state (fn [_] {:detailpage/data {}}) If i structure the initial-state to something more standard e.g. :initial-state (fn [_] {:detailpage/data (comp/get-initial-state datans/DataResponse)}) the app state is changed to reflect just that The contents of the state for DataResponse are overwritten to reflect whatever structure has been supplied in the initial-state calls in DataResponse Firstly - does this make sense? and, does this sound right? I might be confused about the role of initial-state I have tended to use it to reflect the hierarchical structure of components but is its purpose purely to inject data for "first-frame" rendering In summary, I can get the behaviour I want by setting initial-state to empty maps Is that what I should be doing?

tony.kay 2026-04-13T17:54:45.564259Z

The core purpose of initial-state is, as you said, making sure there is something in the database on the first frame for things that need to be there for the first frame. But, since it is a callable function, some libraries/applications/features use it to help with dynamic cases as the “initial state once the thing is put in place”. The add-route-target! is just one of these cases: You’re adding something to the system after the first frame that was never there (and therefore has no state). Depending on your load order and call order, you could easily cause yourself some problems, since the routing system will try to make things work using initial state (which is why it takes initial state params as an argument, in case it needs them). A route isn’t going to query props properly unless it’s joined to the graph. So, even an empty map is enough. Of course managing the rest of your “application process” from there is kind of up to you (loading data, etc.). You can use the routing hooks for that, or put your logic into a statechart or state machine and have the statechart or machine control the triggers to routing. The difficulty there is then you have a state machien running for each router (defrouter) AND a user-land state machine/chart which can get out of sync (e.g. machine doesn’t know the route has changed) This is why I’m moving more of my stuff to the statecharts library where I’ve added a new routing system. It’s still alpha but we’re integrating it into a project now, so it should stabilize quickly. The advantage of a statechart is that you formalize all of this process into a unified visualizable chart that makes all of these interdependencies more explicit, and “forces” the route based on the active state. The semantics get a lot cleaner.