Flux Architecture
上QQ阅读APP看书,第一时间看更新

Application data and UI state

When we have a separation of concerns that sticks presentation in one place and application data in another, we have two distinct places where we need to manage state. Except in Flux, the only place where there's state is within a store. In this section, we'll compare application data and UI data. We'll then address the transformations that ultimately lead to changes in the user interface. Lastly, we'll discuss the feature-centric nature of Flux stores.

Two of the same thing

Quite often, application data that's fetched from an API is fed into some kind of view layer. This is also known as the presentation layer, responsible for transforming application data into something of value for the user—from data to information in other words. In these layers, we end up with state to represent the UI elements. For example, is the checkbox checked? Here is an illustration of how we tend to group the two types of state within our components:

Two of the same thing

This doesn't really fit well with Flux architectures, because stores are where state belongs, including the UI. So, can a store have both application and UI state within it? Well, there isn't a strong argument against it. If everything that has a state is self-contained within a store, it should be fairly simple to discern between application data and state that belongs to UI elements. Here's an illustration of the types of state found in Flux stores:

Two of the same thing

The fundamental misconception with trying to separate UI state from other state is that components often depend on UI state. Even UI components in different features can depend on each other's state in unpredictable ways. Flux acknowledges this and doesn't try to treat UI state as something special that should be split off from application data.

The UI state that ultimately ends up in a store can be derived from a number of things. Generally, two or more items from our application data could determine a UI state item. A UI state could be derived from another UI state, or from something more complex, like a UI state and other application data. In other cases, the application data is simple enough that it can be consumed directly by the view. The key is that the view has enough information that it can render itself without having to track its own state.

Tightly coupled transformations

Application data and UI state are tightly coupled together in Flux stores. It only makes sense that the transformations that operate on this data be tightly coupled to the store as well. This makes it easy for us to change the state of the UI based on other application data or based on the state of other stores.

If our business logic code wasn't in the store, then we'd need to start introducing dependencies to the components containing the logic needed by the store. Sure, this would mean generic business logic that transforms the state, and this could be shared in several stores, but this seldom happens at a high level. Stores are better off keeping their business logic that transforms the state of the store tightly coupled. If we need to reduce repetitive code, we can introduce smaller, more fine-grained utility functions to help with data transformations.

Note

We can get generic with our stores as well. These stores are abstract and don't directly interface with views. We'll go into more detail on this advanced topic later in the book.

Feature centric

If the data transformations that change the state of a store are tightly coupled to the store itself, does this mean that the store is tailored for a specific feature? In other words, do we care about stores being reused for other features? Sure, in some cases we have generic data that doesn't make much sense in repeating several times across stores. But generally speaking, stores are feature specific. Features are synonymous with domains in Flux parlance—everyone divides up the capabilities of their UI in different ways.

This is a departure from other architectures that base their data models on the data model of the API. Then, they use these models to create more specific view models. Any given MV* framework will have loads of features in their model abstractions, things like data bindings and automatic API fetching. They're only worried about storing state and publishing notifications when this state changes.

When stores encourage us to create and store new state that's specific to the UI, we can more easily design for the user. This is the fundamental difference between stores in Flux and models in other architectures—the UI data model comes first. The transformations within stores exist to ensure that the correct state is published to views—everything else is secondary.