Skip to content

The AFib State

AFib maintains a single, global, immutable state that fully describes your application's data and UI.

Given an instance of this state, AFib can build the user interface that corresponds to that state. AFib's state has two primary areas: the route state and the global component state.

The Route State

In AFib, each screen, drawer, dialog, bottomsheet, and AFib-aware widget has a route parameter. This is an object which contains data that lives for as long as the UI element does (though technically it can live longer, its best to think of it as transient data associated with that UI element).

The route state keeps track of all the active route parameters for you. When your UI renders, AFib will find the appropriate route parameter and pass it to your rendering function.

The route state has two areas.

The Route Hierarchy

The route hierarchy keeps track of a hierarchy of screens the user is currently visiting. For example, perhaps the user has started at the home screen, navigated down to a search screen, and then clicked on one of the results to navigate down to a details screen. The hierarchy would then contain three screens (home/search/details), each with its own route parameter.

If the user clicks the back button on the details screen to go up a level, they would return to the search screen, and the route parameter for the details screen would be removed from the route hierarchy.

Route parameters in the screen hierarchy linger slightly

When an animation occurs as you move between screens, Flutter re-renders both the new and old screen. As a result, AFib keeps the route parameter for a screen that is going out of scope around during the animation. It technically remains in a holding area until the navigation completes.

The Global Route Parameter Pool

AFib also allows you to create route parameters that live indefinitely. The route parameters for dialogs, bottom sheets, and drawers are stored in the global route parameter pool. Screens and widgets can also reference global route parameters if you like.

Child Route Parameters

Each screen, whether its route parameter is in the hierarchy or the global pool, has a pool of child route parameters associated with any AFib-aware child widgets on that screen. These route parameters are identified by a widget identifier.

Although AFib-aware widgets will often have their own route parameters in this child pool, they can also reference other existing route parameters. For example, it is sometimes useful for a child widget to reference the route parameter of its parent screen, rather than having its own.

The Global Component State

The global component state contains state that is not associated with a specific screen, but is used throughout your app and exists for as long as your app is running. Data in the global state is often loaded from and synchonized with a persistant store (sqlite, Firebase Firestore, data behind a REST api, data behind device APIs, etc).

Initially, your app will have a single component state, called XXXState, where XXX is your project code. XXXState will hold references to objects that contain the business state of your app. By convention, the classes referenced directly by your component state are suffixed with "Root", as they are at the root of your state.

For example, in the todo list app from the tutorial, the TODOState contains TodoItemsRoot, CategoriesRoot, UsersRoot, UserCredentialRoot objects. This data might be used from multiple screens within your app, and wouldn't go away just because the user navigated to a different screen. It will go away, however, if the app itself restarts, which is why it is generally synchronized with data in an external persistent data store.

Third Party States

AFib allows third party components to have their own state. Each third party component has its own project code. For example, AFib's Chat Support library uses the code AFCS, its component state is stored under under AFCSState.

Root State and Revising Immutable State

The entire AFib state is immutable. In order to change it, you will always make a copy of it. When you update data within AFib, you will propagate the copy-on-write changes up until you get to one of your root states. AFib provides APIs for updating root state objects.

If you are unfamiliar with using immutable data structures, note that they are far less inefficient than you might fear, and make the state of your app much easier to understand. A subsequent section explains how to design immutable state that is easy to maintain.

State Views

When AFib renders a UI element, it passes a state view to that element. A state view consolidates data from one or more component states into a single object.

Although you can create state views which contain a subset of the component state in order to reduce rendering frequency, doing so for performance reasons is very, very rarely necessary. Most applications can get by with a single state view.

What's Next?

Next, we will learn how AFib helps you convert your state into a user interface.