State management is probably one of the most misunderstood and overused technologies in front-end development today, with many developers starting with scaffolding for Vue buckets or React Redux/Mobx buckets. Then use a state management library like Redux on some simple presentation pages, which is actually not a best practice.

What is state management

In recent years, with the rise of single-page applications, JavaScript needs to manage more state, or data, than ever before. These states may include server responses, cached data, locally generated data that has not yet been persisted to the server, and UI states such as active routes, selected tags, Whether to display loading effects or pagers and so on, these are all challenges that web development didn’t face ten or twenty years ago.

But in fact, no matter how complex the system is, the front-end page to complete the thing is actually very simple, is to render out the business information, feedback to the user, and human-computer interaction, back to the server, this is the core problem solved by the front-end technology. And almost all web systems will not maintain some of the user’s data and the state of the system in the client, such as the user’s membership level, the newly added to-do items only saved in the browser, because these are “fleeting” things, users change a browser these information will all disappear. So the data (state) will be stored on the server, and when the user logs in again, the page will retrieve the latest data from the server and render the page.

Since the birth of Ajax, the Web application does not need to communicate with the server a lot and frequently. The server originally needed to return the data of the entire page, but now only needs to pass a small amount of information through Ajax, and the rest of the page is manipulated by javascript, tinker with the elements of the page. Because there is no need to refresh the entire page, this Kind of Ajax application has a very good user experience and gives a very fast feeling. And the overall process of Javascript operations on the page is actually the synchronization of the page UI and Javascript variables, and also involves the synchronization of server data, which is called state management.

Generalized state management

State management is a very broad concept because state is everywhere. Frameworks like Spring manage state, components like RDS and Redis store data, and mobile apps store data in the phone’s memory. State management is nothing new. Before the Web front end got complicated, Many system web pages use pure Javascript or jQuery to do some state management, or some data management bar, of course, here side to do things are actually very complex, mainly manifested in the state synchronization, you can see the following example.

Javascript frameless age state management example

AddBook (book) {// js state logic this.books.push(book); // Synchronize the server logic this.callAddBookAPI (book).then(this.ajustuibook); / / UI logic (synchronous) enclosing mayBeDoSomethingElse (); const li = document.createElement('li'); const span = document.createElement('span'); span.innerText = book.name; this.$bookUl.appendChild(li); li.appendChild(span); }Copy the code

In the above code, we add a Book from a form. The addBook method first adds the Book to the local books variable, and then asks the server to pass the new Book information. The result may or may not be successful, so we call a callback method to adjust it. You then manipulate the Dom to update the presentation of the page. Of course, there are more complicated cases, such as somewhere else on the page, where there might be a count of all Books, or a display of “the user’s most recent Books,” where the program needs to find the Dom of those elements and update the Dom content with domain-specific logic.

In fact, today in 2019, I can still see some familiar bugs on many mobile apps. For example, I saw an in-app message on Xianyu, but when I checked the message page, I didn’t see it in the corresponding contact message box, so I had to refresh it. This should be a typical example of poor status management.

This kind of problem can become very complicated in large Web applications, and Facebook’s Web applications are plagued by such problems.

Facebook’s problems

Facebook’s site was one of the first to start the concept of Web App. Before Facebook created the Flux architecture, There were a lot of unsynchronized state bugs on Facebook. I have witnessed these bugs in the few times I rarely used them. You know, when you’re on Facebook and you get a couple of notifications, but when you click on it, it’s gone, and after a while, it comes back, and you click on it and you see the previous message, but the new one still hasn’t come.

Although Facebook’s client structure is not the same as the popular MVC or MVP architecture, the cause of their problems is probably at fluxxor.com/what-is-flu… It’s described like this

Fluxxor.com/what-is-flu…

To best describe traffic, we compare it to one of the leading client architectures: MVC. In a client-side MVC application, user interaction triggers code in the controller. The controller knows how to coordinate changes to one or more models by calling methods on them. When the model changes, they notify one or more views, which in turn read new data from the model and update it so that users can see the new data.

A simple MVC flow

As MVC applications grow and controllers, models, and views are added, dependencies become more complex.

With just three views, a controller, and a model, it’s already hard to keep track of dependency diagrams. Multiple branch code paths are executed when the user interacts with the UI, and debugging in application state becomes an exercise in figuring out which module (or modules) of one (or more) of these potential code paths contains errors. In the worst case, user interactions trigger updates, which in turn trigger other updates, leading to error-prone and difficult-to-debug cascading effects along some of these paths, sometimes overlapping.

Flux eschews this design in favor of one-way data flow. All user interactions in the view invoke the action creator, which causes action events to be emitted from the singleton scheduler. The scheduler is the single launching point for all actions in a flux application. The action is sent from the scheduler to the store, which updates itself based on the response.

In fact, in the same period, Facebook React was designed together with Flux, and the brilliant React swept the whole front end. At the same time, inspired by Flux, state management officially came into the eyes of many developers, and state management began to come into the eyes of people in a standardized way.

Current Web State Management (narrowly defined state Management)

State management has now become a topic in the front-end development stack, with rich toolsets and frameworks. Now, when it comes to state management, the concept is still very broad, but it converges to a few points.

  1. Directional management of data flows, such as Flux
  2. Framework tool management of system state, e.g. Redux, Mobx
  3. State management during the component lifecycle, for example used in ReactsetStateorhooks
  4. .

In fact, when front-end development talks about state management, it means something like Redux, which guides the entire system with the idea of a single data stream, and stores state in a specific place, in the UI component layer with some selector that pulls out the required components and renders them onto the UI.

Redux is not the only tool library for state management. Mobx, Vuex, etc., are excellent libraries with similar ideas.

Of course, I’ve seen quite a few applications that don’t use a state management library, but write their own state management solutions by hand. (In fact, this is not difficult at all, because libraries like Redux are actually quite simple. The early Redux libraries were only a couple of hundred lines of code.) The Angular technology stack, for example, uses Rxjs for simple state management through the Angular Service carrier. React, for example, is also used to connect to a custom state management service directly through singletons or hooks. These methods have their own ways in both large and small projects. The business of state management design doesn’t have to be confined to a framework and a tool library; it can even have its own play within a tool library.

While the definition of state management is actually very broad and there are many good practices, there are a few principles to follow for good state management.

1. The UI layer

In back-end development, domain-driven design (DDD) requires isolating the business model, making it infrastructure-independent and non-intrusive, and using Adaptor to isolate network, database, and other operations. The nice assumption is that if you do a major refactoring or change the Web framework, Just replace the outer Adaptor layer of the architecture, leaving the domain layer unchanged.

This principle also applies to the front end, but now the front end is component-driven era, the core domain of the front end is the UI layer, good state management should make the UI layer independent, and let the logic of state management as little as possible to invade the UI layer. Another idea is to keep the purity of the UI layer, as long as the same data to the UI layer, it should be of the same signs, then later in a state management scheme, or some Api level changes, or is the introduction of BFF, reduce the burden of the front-end logic, so the changes you just need to finish in the field of state management of, The UI layer can be left untouched, which greatly reduces the context burden of front-end development and is very unit testing friendly.

Some of the front-end application logic is also heavy and complex, which is a different matter. In addition to the UI layer, those core logic should also be modeled and layered to maintain dual cores. However, with the exception of some rich applications (e.g. mind mapping applications, tools like DRAWIO), I strongly recommend not putting much domain/business logic on the front end.

2. Single data sourceandUnidirectional data flow

A single data source and the one-way data flow is the key to the management of state, it can make the application from a state of a mess, a single data source requires the client application of critical data should be obtained from the same place, and one-way data flow requirements within the application state management of the participants are to obtain data in a flow direction and action, not allow two-way exchange of data, the following figure

A single data source and the one-way data flow looks like these two concepts, also contact with each other, a single data source to ensure the UI rendering of simple, only need to respond to a single source of data on what data is through the predictable data transformation UI, not wrong, it is just like the “law of watch”, if there are two boss you command, You don’t know what to do. Unidirectional data flow can be traced by limiting the flow of data and actions, and can realize some log printing, hot loading, time travel, isomorphic applications and other functions. Another function is to implement Inversion of Control for state changes at the UI layer, so as to achieve decoupling.

For example, in Redux, a page renders a list of books. The books variable is retrieved from the Store, which is a one-way data flow. But to add a book, we call an API to createBook. The new book is added to the list directly after an asynchronous Action is invoked in the component or the request is invoked via HTTP. This is a classic mistake that violates both a single data source and one-way data flow. In many cases, this means that the state of the application becomes fragmented again, reverting to chaos, synchronization failures, and bugs.

It is important to note that not all variables should be packed into the store of a single data stream. States in some components should complete their life cycle within the component, for example, isSelecting state of a Selector, or isOpen state of a Modal. These are component states and do not need to be entered into the global state tree.

Benefits and problems of state management

And finally, to get back to why do state management

State management has the following benefits

  1. Effectively separate UI layer from data processing layer
  2. Helps the front end apply structured data
  3. Effectively control state changes
  4. Handles synchronous and asynchronous
  5. To achieve some log printing, hot loading, time travel, isomorphic applications and other functions
  6. .

Has its drawbacks as well as state management, of course, in fact just a little, is the code becomes more complex, of course, this is not weakness, when an application business use cases and code rate rising, code cannot keep simple and concise, without a good architecture constraints, so only turn into a big trouble, but design a good state management plan, Then you can keep complexity within a reasonable range and keep your architecture clean.

The original address