IO /learn-vuex-…

Introduction: While learning vue. js recently, I saw a foreign article that described how to use vue. js and Vuex to build a single page application of simple notes. I feel I have gained a lot. Based on its examples, I have carried out some optimization and custom functions. Here I would like to share my learning experience with you.

In this tutorial we will learn how to use Vuex in our Vue project by building a note-taking application. We’ll walk you through what vuex.js is, when to use it in a project, and how to build our Vue application.

Here’s a preview of our project:

Project source: vuex-Notes-app; Students in need can directly download the source code to view.

Main knowledge points

Vuex overview

Before we jump into the project, it’s best to take a few minutes to understand the core concepts of Vuex.

Vuex is a centralized state management architecture designed specifically for vue.js applications. It borrows design ideas from Flux and Redux, but simplifies concepts and uses an implementation specifically designed to better leverage vue.js data response mechanisms.

The concept of state may feel a little vague at first contact. Simply speaking, state is regarded as a collection of data used in our project. Vuex then makes a difference between component local state and application state.

  • Component local State: This state represents a state that is only used within a component, similar to what is passed inside a Vue component through configuration options.

  • Application Level State: Indicates the application level state that is shared by multiple components.

Consider a scenario where we have a parent component that contains two children. The parent component can easily pass data to the child component using the props property.

But the question is, how do our two child components communicate with each other? Or how does a child component pass data to its parent? When our project was small, neither of these issues was too difficult because we could communicate with the parent and child components through event dispatches and listeners.

However, as our project grew:

  • It becomes difficult to keep track of all events. Which event is dispatched by which component, and which component should listen for which event?

  • The project logic is scattered among various components, which easily leads to the confusion of logic, which is not conducive to the maintenance of our project.

  • The parent component will become increasingly coupled to the child component because it needs to explicitly dispatch and listen for certain events of the child component.

This is the problem Vuex is designed to solve. The four core concepts of Vuex are:

  • The State Tree: Vuex uses a single state tree that contains all application-level states in a single object. At this point it exists as a “unique data source (SSOT)”. This also means that each app will contain only one Store instance. Single-state trees allow us to directly locate any particular state fragment and easily take a snapshot of the entire current application state during debugging.

  • Getters: Used to get Vue component data from the store.

  • Mutators: Event handlers used to drive changes in state.

  • Actions: A function that can be used by the component to drive mutations, the event handler

If you don’t quite understand these four concepts, don’t worry, we will explain them in detail in the actual project later.

The following chart explains in detail the flow of data in Vuex applications (official Vuex chart)

A quick explanation:

Vuex specifies that states belonging to the application level can only be modified by methods in Mutation, and events in Mutation distribution can only be modified by actions.

From left to right, we call actions from the component. At the action level, we can interact with background data, such as fetching initialized data sources, or filtering intermediate data. Mutation is then dispatched in the action. Mutation triggers a state change, which triggers a view update.

Matters needing attention

  • The data flow is one-way

  • Components can invoke actions

  • Action is used to distribute mutations

  • Only mutation can change the state

  • The store is responsive, so whenever the state is updated, the component is updated synchronously, right

Environmental installation

The application will use Webpack for module packaging, processing, and hot restart. Use Vue official scaffolding Vue – CLI.

Install the vue – cli

npm install -g vue-cliCopy the code

Node.js >= 4.x, 5.x is best

Initializing the application

Vue init webpack vue-notes-app CD vue-notes-app NPM install // Installs the dependency package NPM run dev // starts the serviceCopy the code

Initialize an application with the project name vue-Notes-app and choose to use webPack packaging. On the cli, select the initial configuration item as prompted. When selecting JSLint validation, the AirBNB specification is recommended.

Use your favorite editor to open our new project, which looks like this:

  • The Components/folder is used to store our Vue components

  • Vuex/folder contains vuex Store related items (State Objects, Actions, Mutators)

  • Build/files are packaged build configuration files for Webpack

  • The config/ folder contains some configuration items, such as port configuration for our server to access, etc

  • Dist/This folder does not exist at first and will be produced after our project is built

  • The app. vue root component, where all child components will be referenced

  • The index.html entry file for the entire project will reference our root component app.vue

  • The JS logic of the main.js entry file will be injected into index.html after webpack is packed

Function module

  • Add note, add a note, edit area shows empty note content

  • Delete notes. After deleting a note, the edit area displays the first item of the current note category

  • Note list switch, divided into all notes and favorite notes, after the switch, the editing area displays the first note in the current list

  • Bookmark notes. Label the currently active notes as bookmarks

Project component division

In this project, we will use a total of four components: the root component app. vue, the action bar component tool. vue, the table component Noteslist. vue, and the note editing component editor. vue.

Create Vuex Store

Following the function modules we listed above, we create a store.js file under Vuex/.

import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); // State to maintain const state = {notes: [], activeNote: {}, show: "}; Const mutations = {// initialize state INIT_STORE(state, data) {state.notes = data.notes, state.show = data.show; state.activeNote = data.activeNote; }, // NEW_NOTE(state) {var newNote = {id: +new Date(), title: ", content: ", favorite: false}; state.notes.push(newNote); state.activeNote = newNote; }, // edit the note EDIT_NOTE(state, note) {state.activenote = note; For (var I = 0; i < state.notes.length; i++) { if(state.notes[i].id === note.id){ state.notes[i] = note; break; }}; }, // delete notes DELETE_NOTE(state) {state.notes.$remove(state.activenote); state.activeNote = state.notes[0] || {}; } / / switch note collection and cancel collection TOGGLE_FAVORITE (state) {state. ActiveNote. Favorite =! state.activeNote.favorite; SET_SHOW_ALL(state, show){state.show = show; // Switch data display, Need to be synchronized update activeNote if (show = = = 'favorite') {state. ActiveNote = state. Notes. The filter (note = > note. The favorite) [0] | | {}; }else{ state.activeNote = state.notes[0] || {}; }}, // set the currently activeNote SET_ACTIVE_NOTE(state, note) {state.activenote = note; }}; export default new Vuex.Store({ state, mutations });Copy the code

Create Vuex Actions

Create an action.js file under Vuex/ that will be used by the component.

function makeAction(type) { return ({ dispatch }, ... args) => dispatch(type, ... args); }; Const initNote = {id: +new Date(), title: 'My note ', content:' Favorite ', false}; // Simulate initializing data const initData = {show: 'all', notes: [initNote], activeNote: initNote}; export const initStore = ({ dispatch }) => { dispatch('INIT_STORE', initData); }; Export const updateActiveNote = makeAction('SET_ACTIVE_NOTE'); // Update the current activeNote object export const updateActiveNote = makeAction('SET_ACTIVE_NOTE'); // add a note object export const newNote = makeAction('NEW_NOTE'); Export const deleteNote = makeAction('DELETE_NOTE'); export const toggleFavorite = makeAction('TOGGLE_FAVORITE'); export const editNote = makeAction('EDIT_NOTE'); Export const updateShow = makeAction('SET_SHOW_ALL');Copy the code

Create Vuex Getters

Create a getter.js file under vuex/ to get data from store.

Export const filteredNotes = (state) => {if(state.show === 'all'){return state.notes || {}; }else if(state.show === 'favorite'){ return state.notes.filter(note => note.favorite) || {}; }}; All or favorite export const show = (state) => {return state.show; }; // get the current activeNote export const activeNote = (state) => {return state.activenote; };Copy the code

The above is all the logic of Vuex. After determining the functions we need to complete, the next step is to call the action in the component to realize the corresponding functions.

The routing configuration

Here we will use vue-Router for routing, referring to the bootstrap style.

index.html



  
    
    vuex-notes-app
    
  
  
    
       
Copy the code

We’ll write all the entry logic in main.js

main.js

import Vue from 'vue'; import App from './App'; import VueRouter from 'vue-router'; import VueResource from 'vue-resource'; // Routing module and HTTP module vue. use(VueResource); Vue.use(VueRouter); const router = new VueRouter(); router.map({ '/index': { component: App } }); router.redirect({ '*': '/index' }); router.start(App, '#app');Copy the code

The root component App. Vue




  html, #app {
    height: 100%;
  }

  body {
    margin: 0;
    padding: 0;
    border: 0;
    height: 100%;
    max-height: 100%;
    position: relative;
  }



Copy the code

There are three child components referenced in the root component: tool. vue, Noteslist. vue, and editor. vue.

Note: We added a vuex option in the configuration to expose the methods defined in our action. The only thing we did in the root component was initialize the mock data. So we call initStore in actions during the ready phase of the component lifecycle to initialize the state in our store

Toolbar.vue

#toolbar{ float: left; width: 80px; height: 100%; background-color: #30414D; color: #767676; padding: 35px 25px 25px 25px; .starred { color: #F7AE4F; } i{ font-size: 30px; margin-bottom: 35px; cursor: pointer; Opacity: 0.8; 0.5 s help ease the transition: opacity; &:hover{ opacity: 1; }}}Copy the code

An example of Vuex used here is that we need to know if the currently active note is a favorite. If so, we need to highlight the Favorite button, so how do we know? Getters in vuex gets the active note object and determines whether its favorite is true.

Keep in mind that data in Vuex is one-way and can only be retrieved from the Store, whereas in our example activeNote is always maintained in store.js so that it can be shared with other components

// State to maintain const state = {notes: [], activeNote: {}, show: "};Copy the code

NotesList.vue



Copy the code

Note list component, which has three main operations

  • Apply colours to a drawing notes

  • Switch render Notes

  • Click the list title to switch to activeNote

We get the list of notes through the filteredNotes method in getters

Export const filteredNotes = (state) => {if(state.show === 'all'){return state.notes || {}; }else if(state.show === 'favorite'){ return state.notes.filter(note => note.favorite) || {}; }};Copy the code

As you can see, the list we get is dependent on the state.show state. We just call actions to update state.show, so we dynamically refresh the list of data, and we do all the tree operations by calling actions.

We also need to update activeNote dynamically while switching lists. Take a look at how we do it in store.js:

SET_SHOW_ALL(state, show){state.show = show; // Switch data display, Need to be synchronized update activeNote if (show = = = 'favorite') {state. ActiveNote = state. Notes. The filter (note = > note. The favorite) [0] | | {}; }else{ state.activeNote = state.notes[0] || {}; }}Copy the code

What triggers these actions is that we bind our custom functions to the two buttons, pass different parameters to the functions, and then call the methods in actions to filter and update the data.

Editor.vue



Copy the code

In the editor. vue component, we need to be able to update the contents of the current activeNote component and the corresponding note object in the list that we are modifying in real time.

As mentioned earlier, it is not allowed to modify the store.js state directly in the component, so we assign the store state value to an object using a calculation property, and then call the action in our custom updateNotes() method. We’re also passing in the currentNote object.

In store.js, what we do is we find the object with the corresponding ID and reassign it, because as mentioned earlier, our data is reactive, and we change it here, and the corresponding view is refreshed and changed, and we have real-time editing, real-time rendering.

EDIT_NOTE(state, note) {state.activenote = note; For (var I = 0; i < state.notes.length; i++) { if(state.notes[i].id === note.id){ state.notes[i] = note; break; }}; },Copy the code

Q&A

In this project, we did not introduce vue-Resource plug-in, just simulated part of the data, interested students can have a try.

Since our example is relatively simple and does not involve very in-depth things, the deeper research needs more time to practice.

Finally, in action, we can do more things, such as dynamically and asynchronously retrieving notes according to ID, etc. These interested students can try to enrich the example bit by bit.