Part 1: State management for modern frameworks
State management is hard
At some point or another when building an application, you will have to create a login system. On the surface, it seems simple. Someone is logged in or they aren’t. What’s so hard about that? Once you dive into the implementation, things can get complex pretty quickly. Let’s talk about all of the possible states your app can have.
- Initial state: The user is not logged in. This is the default state of the app and the easiest to deal with. As soon as a user attempts to login, the state of the app gets more complicated.
- UI state: There is the state of the UI itself. Are the inputs valid? Any client-side validations that need to be run and displayed?
- API state: There is the state of the API. Was there an HTTP error? Did the user authenticate successfully?
- Auth state: After a successful authentication response, there may be role checks depending on the resource they are trying to get to etc. What if you have to use tokens for subsequent API requests? Is the token valid? Has it expired? Do we need to refresh the token?
Many of these operations are asynchronous too. As you can see, things can get complicated pretty fast. So how do you manage complex state changes without introducing complex logic, handle asynchronous data, and avoid code that is brittle and hard to test? The Flux Pattern was created to answer that question.
What is Flux?
Flux data flow in depth
The data flow starts with an Action call (which is usually called by a View), which is then sent to the Dispatcher. The Dispatcher broadcasts the resulting payload which updates the Store. The final piece is displaying the state change in the View. The View “listens” to the state changes on the Store and re-renders itself if necessary. This allows for atomic operations to flow through the system in a predictable way. Views only care that the data has changed and it needs to re-render. This simplifies where changes come from and how those changes are tracked since there is one way data flow. State changes are created, ran and handled linearly. If you’re looking to further your understanding of the Flux pattern I have found Facebook’s documentation to be a great resource.
Flux + Reactive Frameworks AKA The View
Why Flux when we have props?
If you are familiar with ReactJS or VueJS, you have worked with props on a component. Why use a global store if you can let a component re-render if a prop changes on the component? Why not pass around component props throughout your app vs. using a global store? Sometimes a Flux library isn’t necessary. However, there are instances where you would want to use Redux or Vuex instead of passing props or data around. Having a parent component pass props to a child component is pretty simple. It starts to get messy when you have components that aren’t siblings or children of a parent component but need access to the same data. This is what is referred to as “Prop Drilling”. This passing around props can make data changes difficult, and keeping track of the cross-stitch pattern of props will make your brain hurt on larger projects.
Flux to the rescue
Redux or Vuex gives us a global store, and we can declaratively describe which components need to re-render when the state changes in the store. That means, we can start a state change in one component and let all other components that need to re-render update themselves. This takes the burden off of having to logically figure out how to pass around the right props to each and every component in the component tree that need to re-render. In order to understand how this works in practice, in the next blog post we will write our own Flux implementation for VueJS following the same API as Vuex. This will be a deep dive into how VueJS manages its reactivity and how we can create a global store to tie into it.
Part 2: Implementing a Flux library for VueJS
In part 2, we will start by creating a VueJS plugin that becomes our state store. We will match the Vuex API as close as possible and figure out how VueJS implements its reactivity.