使用Vuex和特定于组件的数据构建Vue

时间:2016-11-27 12:57:49

标签: api structure vue.js directory-structure vuex

我看到很多使用这种结构的Vue.js项目:

├── main.js
├── api
│   └── index.js
│   └── services           #containing files with api-calls
│       ├── global.js
│       ├── cart.js
│       └── messages.js
├── components
│   ├── Home.vue
│   ├── Cart.vue
│   ├── Messages.vue
│   └── ...
└── store
    ├── store.js
    ├── actions.js  #actions to update vuex stores
    ├── types.js
    └── modules
        ├── global.js
        ├── cart.js
        └── ...

(此结构的示例为“Jackblog”。)

因此,例如,Cart.vue想要更新Vuex中的inCart数据。为此,购物车导入actions.js

import { inCart } from '../../store/actions'

actions.js导入api的index.js,以便它可以连接到api。然后它会更新Vuex商店中的值。

好的,这对我来说很清楚。但现在,我想研究Messages.vue模块。此模块也应连接到api以获取所有消息,但不必将结果存储在Vuex中。唯一需要数据的组件是Messages.vue本身,因此它应该只存储在组件的data()中。

问题:我无法在actions.js内导入Messages.vue,因为该操作不应更新Vuex。但我无法将actions.js移动到api目录,因为这打破了将所有添加数据的文件放入store-directory中的存储的逻辑。除此之外,逻辑应放在Messages.vue内。例如,当api返回错误时,应设置本地error - 常量。所以它不能由单独的文件处理。

建议api调用并将其存储在vuex或本地data()中的应用程序结构是什么?放置动作文件,api文件等的位置?在查看Jackblog示例时,它仅支持Vuex数据。如何重组这个以支持两者?

2 个答案:

答案 0 :(得分:6)

我使用axios作为HTTP客户端进行API调用,我在gateways文件夹中创建了一个src文件夹,每个后端都有文件,创建{{3} },如下面的

myApi.js

import axios from 'axios'
export default axios.create({
  baseURL: 'http://localhost:3000/api/v1',
  timeout: 5000,
  headers: {
    'X-Auth-Token': 'f2b6637ddf355a476918940289c0be016a4fe99e3b69c83d',
    'Content-Type': 'application/json'
  }
})

在组件和vuex操作中使用这些相同的实例来获取数据,以下是两种方式的详细信息。

填充组件数据

如果数据仅在组件中使用,例如Messages.vue的情况,则可以使用一种方法从api中获取数据,如下所示:

export default {
  name: 'myComponent',
  data: () => ({
    contents: '',
    product: []
  }),
  props: ['abc'],
  methods: {
    getProducts (prodId) {
       myApi.get('products?id=' + prodId).then(response => this.product = response.data)
       },
       error => {
          console.log('Inside error, fetching products failed')
          //set error variable here
       })
    }
    ..... 

填充Vuex数据

如果您使用专用axios instances维护产品相关数据, 你可以从组件中的方法调度一个动作,它将在内部调用后端API并在商店中填充数据,代码如下所示:

组件中的代码:

methods: {
 getProducts (prodId) {
     this.$store.dispatch('FETCH_PRODUCTS', prodId)
  }
}

vuex商店中的代码:

import myApi from '../../gateways/my-api'
const state = {
  products: []
}

const actions = {
  FETCH_PRODUCTS: (state, prodId) => {
    myApi.get('products?id=' + prodId).then(response => state.commit('SET_PRODUCTS', response))
  }
} 

// mutations
const mutations = {
  SET_PRODUCTS: (state, data) => {
    state.products = Object.assign({}, response.data)
  }
}

const getters = {
}

export default {
  state,
  mutations,
  actions,
  getters
}

答案 1 :(得分:2)

简短回答:考虑到Jackblog示例 - 您只需要从组件中导入“api”,然后直接使用API​​。不要导入操作。在Messages.vue中,忘记商店。您不需要与商店绑定的actions层。你只需要API。

答案很长:在一个项目中,我们有以下内容

  1. Ajax库包装器,提供名为 remote 的函数,该函数接受两个参数:字符串和对象。字符串告诉我们要实现的目标(例如,“saveProductComment”),对象是有效负载(参数的名称和值,将被发送到服务器)。

  2. 每个应用模块都可能包含一个“ routes.js ”文件,该文件使用路由配置映射上面的“字符串”。例如:saveProductComment: 'POST api/v1/products/{product_id}/comment'

  3.   

    注意:我使用术语“app module”表示单个.js.vue文件,该文件被NodeJS或Webpack视为“模块”。我称“app module”为包含与特定域相关的应用代码的完整文件夹(例如:“购物车”模块,“帐户”模块,“评论”模块,等等)。

    1. 我们可以在任何地方致电remote('saveProductComment', { product_id: 108, comment: 'Interesting!' }),然后返回Promise。包装器使用路由配置来构建正确的请求,它还解析响应并处理错误。在任何情况下,remote函数始终返回Promise

    2. 每个app模块还可以提供自己的商店模块,我们在其中定义与模块相关的初始状态,突变,操作和getter。我们使用术语“经理”作为州管理代码。例如,我们可以有一个“ commentsManager.js ”文件,为商店模块提供“评论”。

    3. 在Manager中,我们使用remote函数在Vuex 操作中进行API调用。我们从远程返回Promise,但我们还附加了处理结果的回调。在回调中,我们调用变异函数来提交结果:

    4. newProductComment ({ commit }, { product, contents }) {
          return remote('saveProductComment', {
              product_id: product.id,
              comment: contents
          })
          .then(result => {
              commit('SOME_MUTATION', result.someProperty)
          })
      }
      

      现在,如果我们想在Vuex上下文之外使用相同的API调用,但是直接在组件内部,我们只需要在Vue组件方法中使用类似的代码。例如:

      export default {
          name: 'myComponent',
          data: () => ({
              contents: '',
              someData: null
          }),
          props: ['product'],
          methods: {
              saveComment () {
                  remote('saveProductComment', {
                      product_id: this.product.id,
                      comment: this.contents
                  })
                  .then(result => {
                      this.someData = result.someProperty
                  })
              }
          }
      }
      

      在应用程序结构方面,对我们来说真正重要的是:

      • 将应用程序正确划分为不同的问题;我们称之为“app modules”;每个特定事物的一个模块

      • 我们有一个“modules”文件夹,其中包含每个“app module”的文件夹

      • 在特定的“app module文件夹”中,我们在routes.js处有 routes config,将远程函数first参数映射到路由配置;我们的自定义代码选择HTTP方法,插入URL,做各种花哨的东西,适合我们的需要;但是在剩余的应用代码中的任何地方,我们只是以这种简单的方式使用remote('stuffNeededToBeAccomplished', { dataToAccomplishTheNeed })

      • 换句话说,繁重的工作是在映射和Ajax库包装器中(您可以使用任何Ajax库来实际请求);请注意,这完全独立于使用Vue / Vuex

      • 我们将Vuex商店分成模块;通常,在app模块中,我们使用相应的商店模块

      • 在主入口点,我们导入app模块;每个模块的index.js负责注册Ajax包装器中的路由和Vuex中的商店模块(因此,我们只需要导入,不采取进一步操作,为Ajax和商店模块提供可用的路由在Vuex)