I recently came across a scene while writing a project: a map app had a sidebar with several options in it. When the options changed, the app would request data based on the criteria in the sidebar and put markers on the map. A page can be abstracted into the following structure:

// App.vue

<div>
  <sidebar></sidebar>
  <map></map>
</div>
Copy the code

There are many ways to do this, but I’ll start with two common approaches and end with an alternative but interesting solution.

1. Go directly to Vuex

In general, when multiple components share state, it is a good idea to leave the shared state to VuEX. Processing the above scenario, however, is a bit “cumbersome” because the sidebar is actually a form, and using VUEX would require you to define a mutation for each option, losing the convenience of using the V-Model directly.

Bind an option directly using component state

// sidebar.vue

<input v-model="message">
// ...
data (a) {
  return {
    message: ' '
  }
} 
Copy the code

There is a lot more “template” code when using Vuex to bind an option

// Define state, mutation

state: {
  message: ' '
},
mutations: {
  updateMessage (state. message) {
    state.message = message
  }
}

// sidebar.vue

<input :value="message" @input="updateMessage">
// ...
computed: {
  .mapState({
    message: state = > state.message
  })
},
methods: {
  updateMessage (e) {
    this.$store.commit('updateMessage'. e.target.value)
  }
}
Copy the code

2. Put the state on the parent component

If sidebar and Map have a common parent, this approach is much simpler than the one above. However, as our applications become larger and larger, the sidebar and Map are often separated into smaller components, so it will become very troublesome to pass the props layer by layer to the sub-components.

3. Share component status

We usually write the state within a component as follows:

// ...
data (a) {
  return {
     message: ' '
  }
}
Copy the code

In fact, we can separate the object returned from data () {} as a variable, like this:

const state = { message: ' ' }
// ...
data (a) {
  return state
}
Copy the code

During component initialization, the state object will be vUE “responsive,” which leads to an interesting fact: any component that uses state.message in the template will be updated synchronously when state.message changes.

With this in mind, we can write the status of the sidebar as a separate file that can be imported as a module into other components as follows:

// state.js
export default { message: ' ' }


// sidebar.vue
<input v-model="state.message" />

import state from 'path/to/state.js'
// ...
data (a) {
  return { state }
}


// map.vue
// Use the state of the sidebar in the template
<div>{{ state.message }}</div>

import state from 'path/to/state.js'
// ...
data (a) {
  return { state }
},
created (a) {
  // Request data with the status of the sidebar as an argument
  axios.get('/xxxx'. { params: state })
}
Copy the code

One advantage of this is that you can treat state as an “internal” state in sidebar. Vue and happily use v-model to bind data, and map.vue can easily take state as a parameter request. You can also use ‘state.message’ directly in the map.vue template.

further

In the above scenario, the “responsivity” of state occurs during the initialization of the child components, and I want to be able to proactively complete this at some point at the start of the application. At this point we can use the Vue constructor as follows:

// store.js

import state from 'path/to/state.js'

new Vue({
  data: {
    state
  }
})
Copy the code

State is then “reactive” by importing store.js in the main file main.js.

conclusion

This article presents some thoughts on how to manage the state of the sidebar in this particular scenario