1
votes

My team and I are working on the beginnings of medium~large scale application. It's a Vue 2 client rendered application with and asp.net core back-end. The client will be used to manage tens of thousands of items and their status.The application is in its early stages and we've been thinking of ways that we could re-architect our existing client-side store.

Since all of us are new and our self taught we're not really sure what the best pattern is for data management is in a Vue application.

Is there a recommended pattern for data management in a VueJS application?

Our current pattern this:

        |                  |                                                                      
        |   +-----------+  |                                                                      
        |   |           |  |  +-----------+     +-----------+     +------------+                  
        |   |    API    |---->|           |     |           |     |            |                  
        |   |           |  |  | Router    |---->|  Vuex     |---->| Views/     |                  
        |   +-----------+  |  |           |     |           |<----| Components |                  
        |    ^ |     ^     |  |           |     |           |     |            |                  
        |    | |     |     |  +-----------+     +-----------+     +------------+                  
        |    | |     |     |Vue                        |                                          
        |    | |     |     +---------------------------|-------------------------                 
        |    | |     |                                 |                                          
        |Client|     -----------------------------------                                          
        +----|-|---------------------------------------------                                     
             | |                                                                                  
   +---------|-|------                                                                            
   |Backend  | v                                                                                  
   | +----------+                                                                                 
   | |          |                                                                                 
     | DB       |                                                                                 
     |          |                                                                                 
     |          |                                                                                 
     +----------+                                                                                          

We have an API controller that contains all our API endpoints. When the application is loaded, in the router's beforeEnter function we fetch all the data and then commit that to the Vuex store. Then as the user users the application (adding/deleting/editing) items the store is modified and then Vuex calls the API controller and that data is sent to the back-end.

From the research that we've done the opinions on who should call the API and what kinds of data should Vuex store seem mixed. Some blogs and courses say Vuex is the way to manage your API but forum discussions between respectable Vue community members say otherwise. However, the main issue is given Vue's rapid, ever-changing environment articles and discussions from 2018/19 don't really apply to today's Vue.

The current idea that we have is rather than committing from the router to Vuex, we would pass the data from the router to the view and then have the view commit to the store. Views/components would invoke posts instead of Vuex as well. This would limit the responsibility of the store.

We've also looked at the possibility of using Nuxt.js, but their documentation doesn't provide strict guidance on store/API management.

2

2 Answers

1
votes

TL;DR: You need mix of multiple things when building large-scale Vue.js application (or SPA application) in general.

There is no fixed recommended pattern to do that. The right answer is always - it depends.

Following are the few guidelines that will help:

Layer

In general, there are two ways - horizontal layering and vertical layering. With horizontal layering, system is divided into layers like

App Level Component
  <-- Multiple Views (pages)
        <-- Business Logic Components
           <-- Re-usable lower order components
           and API (Fetch/XHR/Websockets)

Generally Business Logic Components are the once to use API layer modules. These are basically bunch of modules containing various API call and normalizing their responses.

This looks clean but quickly becomes unwieldy with too many components as everything will be within flat folder.

Except API layer, generally other layers are split vertically (by business behavior) into modules and all the associated components and helper code is kept in that module or related sub-modules. For example, in e-commerce software - split into accounts, orders, payments, catalog, etc.

However, vertical layering only helps when you truly have a large-scale application, otherwise, simple horizontal layering is good enough.

Application State

This is where things get tricky. This is a continuous process as app evolves. The thing to exercise here is what makes a Global State and Local State. Imagine an application with Bell icon to indicate unread messages and the same page has somewhere at the bottom a way to read messages (Like Facebook/LinkedIn) where the state must be synced and maintained.

This is an example of Global State and as such it could be maintained in some Top Level common ancestor or even better external data store like Redux or Vuex. Both are equally good. Only such global & shared state should be generally modeled into an explicit state store. Another example is logged in user's details that can be used re

Another criteria to list certain state into store is when you need stuff like Time Travel (Undo and Redo) functionality or want to maintain local persistence for apps like drawing apps, games, etc.

Routing and State Management

Along with global state, routing is another top-level concern of the application. Which comes first is always Global Store, because, routing decisions (guards, prefetching, etc.) might to use global data from the store. So, you will always initialize store first and then use it with router if required.

API Layer

Keep all the API code together since it quickly helps identify duplicates if any. API layer should be as dump as possible, mostly dealing with data normalization, parsing, decoding, adjusting camel/snake casing, etc. API layer should never access information directly from router or global state store. If it needs anything, it should be passed to it by the caller.

However, the story would be different if you are using GraphQL and subscriptions along with it. In that case, it becomes more aware of the context and should be designed as such.

Component design

Keep clear distinction between higher-order and lower-order components. Lower-order components are re-usable like Button, Calendar, DatePicker, Dropdown, etc. They should have no knowledge of application and its business logic. It is like you own mini component library that can be used in any Vue.js application.

Higher-order components is where your application's major magic happens. These are the components that will get data from multiple sources like router/vuex/api, etc. These components are again not flat and are generally split into its own layers.

Only top most components should be allowed to access router and should make data available for its children components. Authorization would be throughout dispersed in the component hierarchy.


There are few links that can help you further:

What is the best Vue-Router practice for very large web applications?

Contemporary Front-end Architectures

0
votes

I think that this image from vuex website explains very well the concern of every element of vuex. Actions call the API and then a mutation for commit the responses received for updating the state of the application. Vue components read the state through getters. When an action commits an update in the status, getters update their values and your component renders the updated data. If you have a vue component that need some data from your API for render, you can dispatch one or more action from the navigation guard like beforeEnter or beforeRouteEnter for loading or updating the application state