The BLoC pattern is most often associated with Flutter (Googles mobile application framework) but as a pattern transcends any one technology. In this blog post we are going to introduce a straight forward way of using this powerful pattern in any Typescript project. We have also released an npm package to make life a little easier and hopefully get some amazing open source coders on board to flesh it out!
What is the BLoC pattern?
Business Logic Components was first introduced at DartConf 2018 by Google employees Paolo Soares and Cong Hui. The pattern was devised as a way to separate business logic away from presentation logic and allow it to be re-used across several different platforms.
One of the main drives for BLoC is the lack of a UI template language in Flutter (Googles application development framework). Where Angular uses HTML and React uses JSX to define UI element hierarchy; Flutter simply uses a declarative approach (a true thing of beauty might we add!). This lack of separate template language does not encourage a natural “best practice” separation of concerns as it’s all just Dart and no markup.
How does BLoC work?
It’s all about the Stream! BLoC makes heavy use of streams. The only way to communicate between the UI and a BloC is via streams; likewise BLoC to BLoC communication is only done via…Streams.
Typically in a solution using BLoC pattern the UI would fire Events to a BLoCs stream which would do some processing and emit a State onto another Stream. That State causes a re-render of the UI component. It should be immediately clear that this makes a very neat separation of concerns. The only shared knowledge between the UI and BLoCs is the shape of the Events and State. The rendering and processing is completely self contained!
Why should we care outside of Flutter/Google/Dart?
While in Flutter circles BLoC is all the rage there is great value in using the same approach in other technologies. With the debate of Angular vs React vs WhatTheCoolKidsUse looking set to continue there is space for an approach that allows portable business logic. What if the dev team decides they just can’t stomach any more Angular and all want to move to React? How clean is the application structure? How much pain is there going to be carving out the Angular parts and porting? What if 6 months later they want to move to a mobile app instead of a we app? That’s another port of the code!
By creating the business logic an application as a set of loosely coupled BLoCs that communicate over Streams we can go as far as creating an npm package and letting the UI and application framework simply import it as a dependency.
Sounds great, how?
RxJs has several specialised types of Observable but one that is particularly well suited to our goals is the BehaviourSubject. This class accepts a value and then emits it to all of the listeners subscribed to it; handily it also emits it’s latest value to new listeners that subscribe. With this in mind it’s behaviour is perfect for making sure everything that cares about a given Stream of data actually has that data delivered to it.
Let’s define a base BLoC class using RxJs, Typescript and a little ES2015 Generator magic!
While there looks like there’s a lot going on here the abstract BLoC class is pretty straightforward.
- Private BehaviourSubjects for our Events and States to live on
- A public Observable called State that emits our latest State (We don’t want people injecting states to our BLoC)
- The constructor wires up the private BehaviourSubjects with our public variables and sets up the subscription to respond to new Events
- DispatchEvent is where we tell our abstract class to call the method defined in the inherited child class
- We make sure any class inheriting this one has a HandleEvent method by marking it abstract
- One other detail here is the use of Generator Methods; in essence they are iterator methods that can be paused and re-started without losing their state. We’ll see why that’s powerful below
- We’ve also made our entire BLoC baseclass generic by providing some base types we will accept as Events and emit as States (type all the things!)
An Example of BLoC in action
While all this effort and type juggling looks good they do combine to create a powerful pattern..
- countBloc extends our base BLoC class and implements its one abstract method HandleEvent
- HandleEvent is a Generator method and therefore can be executed, paused and executed repeatedly without losing it’s state
- HandleEvent is checking to see the incoming Event type and yielding a new State based on the event and any data attached to it
- Take note that we can yield as many times as we like from this method which allows us to deal with various async operations and keep updating the State
- The Event and State classes are self explanatory and are simply conveying data back and forth through the Streams
To keep the blog post UI agnostic we’ll show a basic Typescript example of using the BLoC setup but it should be obvious that whatever your chosen technology the BLoC can be shared across the component tree and it’s Observable State subscribed to.
Although a more technical post it’s well worth getting your head around BLoC and how it can be of benefit to the wider JS community. By simply creating a base class to handle Events and States we’ve cleaned up our business logic and UI logic to the point we could change UI technologies without too much pain!