{"id":373,"date":"2019-05-11T13:50:58","date_gmt":"2019-05-11T12:50:58","guid":{"rendered":"https:\/\/codizon.com\/?p=373"},"modified":"2021-04-14T22:15:03","modified_gmt":"2021-04-14T21:15:03","slug":"unidirectional-flow-for-beginners","status":"publish","type":"post","link":"https:\/\/codizon.com\/2019\/05\/unidirectional-flow-for-beginners\/","title":{"rendered":"Unidirectional Data Flow for Newbies"},"content":{"rendered":"\n
Unidirectional Data Flow<\/em> is a buzz phrase that thrilled development conferences all around the world. There are plenty of frameworks that now use this concept such as State Machines<\/a>, Redux<\/a>, Flux<\/a>, Bloc<\/a>, Mobx<\/a>, among others. These are widely used on all frontend platforms (mobile, web, desktop applications, etc.) regardless of programming language or framework.<\/p>\n\n\n\n First, what does “unidirectional<\/em>” mean? In simple words, it means that data only has one way to be transferred to other parts of an application (i.e., a single input leads to a single output). Have you ever encountered issues like concurrency modification exceptions or race conditions? These can all be tackled with a unidirectional flow approach since only one function and one thread can make changes at a time.<\/p>\n\n\n\n Events<\/em> (or “actions<\/em>“) describe mouse clicks, network call completions, input changes, etc. All are added to the FIFO queue.<\/p>\n\n\n\n A worker thread takes the last state and last event in the queue, and returns a new state.<\/p>\n\n\n\n The transition between states is often called a “reducer”, a “reduce function”, or a “transition”.<\/p>\n\n\n\n The transition should be a blocking function and quick. If it cannot be synchronous, consider running a task in the background and emit a new event when the task starts, finishes, or fails. This type of background task is often called a “side effect” or “middleware”.<\/p>\n\n\n\n An interface (or a “view”) not only adds events to the queue, but also observes the current state and updates itself accordingly. This approach works in a cycle, as shown in the figure below.<\/p>\n\n\n\n Further details will be provided in the following sections.<\/p>\n\n\n\n In general, a state is a structure (class or enumeration) that holds the current status of an application or UI (i.e., components visibility, input values, etc.). To avoid ambiguous modifications, the state should always be immutable – no function or object should be able to modify the values of its fields. Below is an example of immutability.<\/p>\n\n\n\n Mutable classes can be modified at any time:<\/p>\n\n\n\n However, modifications to immutable classes are forbidden by the compiler or result in a runtime exception:<\/p>\n\n\n\n Note: You should also ensure that collection fields are immutable.<\/p><\/blockquote>\n\n\n\n So how then do you reflect the change? The answer is simple: create a new object or make a copy of the existing one. Ideally, check if your programming language supports a A “new state” can be created with a copy of the existing one with some of its fields changed.<\/p>\n\n\n\n Normally, a state class contains a number of fields:<\/p>\n\n\n\n Alternatively, you can use an interface:<\/p>\n\n\n\n Your UI can then observe the current state and update itself to reflect the change:<\/p>\n\n\n\n An event is a class, which describes a user action or an asynchronous task’s result. Each event is added to an event queue and processed sequentially.<\/p>\n\n\n\n Here is an example of how event definitions in an application could look:<\/p>\n\n\n\n A reduce function defines exactly two parameters (previous state and current event) and should immediately return a new state.<\/p>\n\n\n\n Here is an example:<\/p>\n\n\n\n Sometimes, there is a need to run an asynchronous task like an API call or writing to a file, etc. Such a task should be processed in a background thread, potentially adding new events to the queue as a result of its execution.<\/p>\n\n\n\n Here is an example:<\/p>\n\n\n\n There are two types of states: Global<\/em> and Scoped<\/em>.<\/p>\n\n\n\n The global state usually reflects the state of the application, while the scoped one reflects the state of a single view fragment such as a Controller<\/em>, ViewModel<\/em>, Presenter,<\/em> or Bloc<\/em>.<\/p>\n\n\n\n Check out our Android Game Of Life sample project at GitLab<\/a>.<\/p>\n\n\n\n What’s the core idea behind Redux, State Machine, and BLoC patterns?<\/p>\n","protected":false},"author":1,"featured_media":888,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"Times New RomanAsap,","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":""},"categories":[82,81],"tags":[],"_links":{"self":[{"href":"https:\/\/codizon.com\/wp-json\/wp\/v2\/posts\/373"}],"collection":[{"href":"https:\/\/codizon.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codizon.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codizon.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codizon.com\/wp-json\/wp\/v2\/comments?post=373"}],"version-history":[{"count":114,"href":"https:\/\/codizon.com\/wp-json\/wp\/v2\/posts\/373\/revisions"}],"predecessor-version":[{"id":1854,"href":"https:\/\/codizon.com\/wp-json\/wp\/v2\/posts\/373\/revisions\/1854"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codizon.com\/wp-json\/wp\/v2\/media\/888"}],"wp:attachment":[{"href":"https:\/\/codizon.com\/wp-json\/wp\/v2\/media?parent=373"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codizon.com\/wp-json\/wp\/v2\/categories?post=373"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codizon.com\/wp-json\/wp\/v2\/tags?post=373"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}Key Concepts<\/h2>\n\n\n\n
<\/figure><\/div>\n\n\n\n
<\/figure><\/div>\n\n\n\n
<\/figure><\/div>\n\n\n\n
<\/figure><\/div>\n\n\n\n
<\/figure><\/div>\n\n\n\n
State<\/h3>\n\n\n\n
data class MyMutableClass(\n var field: String \/\/ variable\n)\n\nval instance = MyMutableClass(\"hello\")\ninstance.field = \"world\"\nprint(instance.field) \/\/ outputs \"world\"<\/code><\/pre>\n\n\n\n
data class MyImmutableClass(\n val field: String \/\/ constant\n)\n\nval instance = MyImmutableClass(\"hello\")\ninstance.field = \"world\" \/\/ error!<\/code><\/pre>\n\n\n\n
copy<\/strong><\/code> operator.<\/p>\n\n\n\n
data class State(val text: String)\n\nval instance = State(\"hello\")\nval newInstance = instance.copy(text = \"world\")\nprint(newInstance) \/\/ outputs \"State(text=world)\"<\/code><\/pre>\n\n\n\n
data class State(\n val id: String,\n val isLoading: Boolean,\n val data: String?\n)<\/code><\/pre>\n\n\n\n
interface State\n\nclass Loading(val id: String) : State\ndata class Ready(val id: String, val text: String) : State\n\nval instance = Loading(id = \"abc\")\nval newInstance = Ready(id = instance.id, text = \"hello world\")\nprint(newInstance) \/\/ outputs \"Ready(id=abc, text=world)\"<\/code><\/pre>\n\n\n\n
state.observe { currentState ->\n loadingView.isVisible = currentState is Loading\n}<\/code><\/pre>\n\n\n\n
Event \/ Action<\/h3>\n\n\n\n
interface Event\n\nclass OnResetClicked: Event\ndata class OnApiResult(val result: String): Event\ndata class OnApiError(val error: Throwable): Event<\/code><\/pre>\n\n\n\n
Reduce Function \/ Reducer<\/h3>\n\n\n\n
<\/figure><\/div>\n\n\n\n
data class State(val isLoading: Boolean, val data: String?)\ndata class OnApiReady(val data: String)\n\nfun reduce(val previousState: State, val event: OnApiReady): State {\n return previousState.copy(isLoading = false, data = event.data)\n}<\/code><\/pre>\n\n\n\n
Middleware \/ Side Effect<\/h3>\n\n\n\n
<\/figure><\/div>\n\n\n\n
data class State(val isLoading: Boolean, val data: String?)\n\ninterface Event\ndata class OnStart(val id: String): Event\ndata class OnCompleted(val data: String): Event\n\nfun middleware(val previousState: State, val event: OnStart) {\n Thread().run {\n val objectId = previousState.id\n \/\/ make an api call for object with objectId identifier\n \/\/ notify about the result\n addEvent(OnCompleted(\"result for $objectId\"))\n }\n}<\/code><\/pre>\n\n\n\n
Types of States<\/h2>\n\n\n\n
<\/figure><\/div>\n<\/div>\n\n\n\n
<\/figure><\/div>\n<\/div>\n<\/div>\n\n\n\n
Tips<\/h2>\n\n\n\n
Advantages<\/h2>\n\n\n\n
Disadvantages<\/h2>\n\n\n\n
Sample<\/h2>\n\n\n\n
References<\/h2>\n\n\n\n
Conceptual<\/h3>\n\n\n\n
Tools<\/h3>\n\n\n\n
Development<\/h3>\n\n\n\n
<\/figure><\/div>\n\n\n\n