There are some discussions and attempts on front-end data problems encountered in daily work development. In my personal work, the technology stack is mostly VUE, so the rest of the content will focus on this technology stack.

Why are there attempts to do this?

I don’t know if any of you have this situation

When you get a project you need to maintain, the requirements are very simple, fixing bugs, changing function points.

But when you look at the project code, a lot of timesThe project is too complex and the data flow is not clear.



Sometimes we need to modify deep subcomponents whose data sources are the top-level component’s data. Layer by layer through props.

If we are looking for data sources and are not familiar with all the business, then we are in trouble. Often for a small change in functionality, we have to look at all the relevant components and data flows. Of course, some generic UI components or functional components are best isolated from the outer layer by passing data through props.

Data has a huge impact on the cost of engineering maintenance, so let’s take a look at what else data has to do with it.

A little bit of a pain point right now

State management

At present, I gradually encountered some problems in my work. Project engineering is more and more complex, and the nesting of logical modules and component modules is more and more deep.

Moreover, in large projects, the different modules are often decoupled, and the internal state and logic are completely isolated. Similarly, these modules or components are maintained and developed by different students, and they are relatively complete inside.

For example, the architecture design shown below:



At first glance, it looks like a normal VUE project. What’s the difference?

Indeed, the general logic is a generic VUE front-end project.

Through a VUE project or engine, engines like urban planning, government construction, provide

  • Function base, view base
  • Public data state
  • General ability

The various business views and functional modules such as commercial, residential, park, etc. are responsible for their own ecological management, but are based on the overall urban plan. Through this engine, other systems are connected and installed to form a large system. And the key point is:

  • The sub-module is completely independently developed and needs to have its own state management requirements internally.
  • Different modules do not need to understand the business logic and communication mechanism of other modules. All modules have two-way communication with the engine.
  • Submodules can be a relatively closed-loop system, like building blocks, that can be plugged into different vUE root instances. For example, it can be embedded in engine 2 and engine 3, which can effectively support the function building of different projects.

Why is that?

With such an architecture, why can’t state management go directly to VUEX? Imagine developing it as a normal VUE project. Vuex is used for global state management. So what happens as you add more modules?

  • More and more VuEX modules will be maintained.
  • It is coupled to the vuEX of the root instance and depends on the global VUEX for functionality.
  • With the main project there is a risk of code intrusion, logic understanding and complexity.

Another example is a component or UI framework introduced in a project, such as element-UI. It also has a relatively complex combination of components like forms and things like that, how does their state management work? It’s a black box for your project, you don’t have to think about how it needs to manage state, you just have to learn to use it. As you can see, local state management is very useful for components or modules. Local state management comes into being. We need to emulate or organize a form of local state management. In the huge project, to maintain its own side of the world.

Solution ideas

The requirements have already been generated. What are the solutions or ideas that can be implemented?

What can we learn

For state management of data, we want to maintain it locally. There are a number of ways to do this, but we have to consider the migration costs of the project itself and so on. Such as

  • Copy a partial version of vuex
  • Vue3 project, we can try to use the Composition API to implement a hook form of local top-level data logic file. If you are interested in this, you can refer to another article to get a feel for the idea.

Vue3 are you still using Vuex? A new idea of “functional” state management

Reference vuex

Our side is the vuE2 project, and also has the basis of using VUEX. Therefore, it is considered to improve some closed-loop components in a vuEX local manner. Even if these components end up not using this scheme, it is convenient to transition to global VUEX.

On the other hand, if vuex were to be restored seriously, it would be meaningless. There is no need to reinvent the wheel. And the cost is huge, and it may not be done well. After consideration, I decided to extract the ideas and functions and combine them into plug-ins or tools that are most suitable for my business. Briefly review some of the core points of VUex

  • State
  • Getters
  • Mutations
  • Actions
  • Module

Go straight to the practical solution point of view and see what is needed.

  • State, local state management, we need to maintain a local state tree, although different from the global vuEX single state tree. So state is absolutely essential, and state is the basis on which we store our data.
  • Getters, which is equivalent to vuex’s calculated property, goes through another logical calculation when we need to get the state in state. According to the situation, in fact, this layer is not necessary, can consider not included in the scheme.
  • Mutations, the final step in changing state, is the key to enabling devTools to develop plug-ins to track state. We can do without DevTools, but mutations, as the final step, is essential.
  • Actions, which can contain logic for asynchronous functions, then commit to execute mutaions. However, I don’t want to complicate local state management. Asynchronous functions can be written in business logic, and state management is all about processing data. So I decided to set up the abandonment actions mechanism. All state changes are available on the simultaneous function mutations.
  • Module division is still very important, you can divide different types of data into different modules, code readability and maintenance will be much higher.


To a sketch

Ok, try to make a plan. State, mutations, module can already support the existing functions and business requirements.



In fact, with this flow chart, I feel almost, I feel my brain has already run the code, ha ha ha. All I need is a hand. Then you need the technology to implement each of these steps.

Go into a little more detail

Try to implement the whole function according to the simple sketch flow. Review how vuex is used?

  • To configure the object, enter state, mutation, and Action. Divide modules with modules.
  • Components introduce state and helper functions in VUEX
  • Use state in a view or in a calculated or observed property
  • Commit actions or commit to change data in the business logic

Now that I’ve listed this, it’s pretty clear. We can restore these functions “unprofessionally” first. Naturally, the relatively complex logical points of the implementation can be outlined

  • Registry of state and mutation. The configuration object is parsed to complete the registration of state and mutation.
  • When considering registration, we should also respond to the partition of modules in the configuration object, and complete the registration of state and mutation of different modules. Form state state tree and mutation change method tree.
  • After registration, how can we do data hijacking for state? This is the heart of VUE two-way data binding. This allows the view to be updated as the data changes when state is provided for use by different components.
  • When a component uses a local state management plug-in, it exposes some helper methods, as well as the data state itself.

Concrete implementation logic

According to the above several technical points, the code logic is roughly combed, with a simple idea, the implementation of the code is not complex, and has been applied in the business. The effect is actually much more comfortable than the original top-down, parent-to-child data flow.

Parse module, state, and mutation configurations

What is the structure of a Module in VUex

const moduleA = {
  state: () = >({... }),mutations: {... },actions: {... },getters: {... }}const moduleB = {
  state: () = >({... }),mutations: {... },actions: {... }}const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA status
store.state.b // -> moduleB status
Copy the code

To clarify, the requirements and configuration objects can be exactly the same, except that the resolution of actions is omitted. First of all, the first step is of course to parse state, mutations, modules in the configuration object. We need to build two trees, namely the state tree and the mutations tree, and complement the two trees through the namespace of different modules. The code, of course, is all about recursion, type determination, and error cues. The following example is the configuration of the input, and the state tree of the output, and the change method tree.

// Create a store instance based on the configuration object
const store = new myStore({
  state:() = >({
    top:0
  }),
  modules: {a: {state:() = >({
        val1:1.val2:2
      }),
      mutations: {set1(state,value){
          // We need to resolve the state in the same namespace as the current modules
          state.val1 = value
        }
      }
    }
  }
})

// The full state tree after parsing
state = {
  top:0
  a: {val1:1.val2:2}}// Complete mutations tree after analysis
mutations = {
  a: {set1:function(state,value){
      state.val1 = value
    }
  }
} 
Copy the code

The second step is data hijacking of state data. Only by data hijacking of the state tree can the use in the VUE instance be collected, and the render method of the corresponding Vue instance is executed after the data changes to update the attempt. This is also the key point of the MVVM framework. If it is a vUE stack project, super convenient, just need to update the VUE version after 2.6. I’m going to refer to this API

Vue.observable( object )

Make an object responsive. It is used internally by Vue to process objects returned by the data function. The returned object can be used directly in rendering functions and computed properties, and will trigger an update when changes occur.

The react project uses the react data hijacking mode or binding mode to manage the local state of the react project. The implementation is the same with the logic modification. After all, vuex and Redux are similar in usage and logic. The third step

Provide state data and some helper functions

  • Commit The commit method is the function that we use to directly distribute status updates instead of Dispatch. When analyzing and generating the Mutations tree, we simply wrap the function and pass in the corresponding state of the namespace.
// Part of the code, recursively traverses the mutations tree, and processes the state pass in the current namespace as the first argument
const fn = mutations[key]
mutations[key] = function(. params) { fn(state, ... params) }Copy the code
  • Getter The encapsulation of the getter, depending on what you want, is equivalent to the computed properties of the state tree.

Here you can see the code framework of the rough implementation

// partial vuex class Ss {constructor({state, mutations, getters, modules }) { this.state = state this.mutations = mutations this._init(modules || {}) } _init(modules) { if (typeof modules ! == 'object') {throw new Error('moudels configuration parameter is not an object')} /** * @test: none * @msg: Mutations * @param {state, mutations, actions, modules} * @return {state, mutations, actions} */ const moudelsState = getModels('state', modules) this.state = Object.assign(this.state, ... moudelsState) const moudelsMutations = getModels('mutations', modules) this.mutations = Object.assign(this.mutations, . moudelsMutations) /** * @test: none * @msg: Hijacking state content. If react is used, consider seeing what can replace * to determine the vUE version used. * @param {state} * @return {state} */ this.state = vue.Observable (this.state) /** * @test: none * @msg: Mutations ** return {*} */ handlem. call(this, this.state, this.mutations)} /** * @test: None * @msg: submit mutations through commit, so that every change of state has a unified entrance, and the process of change can be easily recorded. * @param {*} type string mutations definition path such as: 'layer.setViews' * @param {*} value * @return {*} */ commit(... res) { ... }}Copy the code

After these three steps, the framework is complete, and the simplest local state management is complete. It’s ready for use. Of course, there are still a lot of capabilities missing, such as strict mode, which only allows commit to commit changes. Exception error supplement during parsing. Add some hook functions, provide some extensible plug-in capabilities, etc. Say so much, also is to provide a thinking train of thought actually only. See more, use more, change more, slowly improve their own cognitive and business ability.