Przeglądaj źródła

docs: review rest of guide

Evan You 8 lat temu
rodzic
commit
977ee4a9a6
5 zmienionych plików z 53 dodań i 167 usunięć
  1. 14 28
      docs/en/forms.md
  2. 1 1
      docs/en/hot-reload.md
  3. 10 8
      docs/en/plugins.md
  4. 12 116
      docs/en/structure.md
  5. 16 14
      docs/en/testing.md

+ 14 - 28
docs/en/forms.md

@@ -15,14 +15,14 @@ The "Vuex way" to deal with it is binding the `<input>`'s value and call an acti
 ```
 ```
 ``` js
 ``` js
 // ...
 // ...
-vuex: {
-  getters: {
+computed: {
+  ...mapState({
     message: state => state.obj.message
     message: state => state.obj.message
-  },
-  actions: {
-    updateMessage: ({ dispatch }, e) => {
-      dispatch('UPDATE_MESSAGE', e.target.value)
-    }
+  })
+},
+methods: {
+  updateMessage (e) {
+    this.$store.commit('updateMessage', e.target.value)
   }
   }
 }
 }
 ```
 ```
@@ -32,41 +32,27 @@ And here's the mutation handler:
 ``` js
 ``` js
 // ...
 // ...
 mutations: {
 mutations: {
-  UPDATE_MESSAGE (state, message) {
+  updateMessage (state, message) {
     state.obj.message = message
     state.obj.message = message
   }
   }
 }
 }
 ```
 ```
 
 
-Admittedly, this is quite a bit more verbose than a simple `v-model`, but such is the cost of making state changes explicit and track-able. At the same time, do note that Vuex doesn't demand putting all your state inside a Vuex store - if you do not wish to track the mutations for form interactions at all, you can simply keep the form state outside of Vuex as component local state, which allows you to freely leverage `v-model`.
+### Two-way Computed Property
 
 
-Yet an alternative approach to leverage `v-model` with state in Vuex store is to use a computed property providing a setter in the component, with all the advantages of param attributes such as lazy, number and debounce.
+Admittedly, the above is quite a bit more verbose than `v-model` + local state, and we lose some of the useful features from `v-model` as well. An alternative approach is using a two-way computed property with a setter:
 
 
-``` html
-<input v-model="thisMessage">
-```
 ``` js
 ``` js
 // ...
 // ...
-vuex: {
-  getters: {
-    message: state => state.obj.message
-  },
-  actions: {
-    updateMessage: ({ dispatch }, value) => {
-      dispatch('UPDATE_MESSAGE', value)
-    }
-  }
-},
 computed: {
 computed: {
-  thisMessage: {
+  message: {
     get () {
     get () {
-      return this.message
+      return this.$store.state.obj.message
     },
     },
-    set (val) {
-      this.updateMessage(val)
+    set (value) {
+      this.$store.commit('updateMessage', value)
     }
     }
   }
   }
 }
 }
 ```
 ```
 
 
-The mutation remains the same.

+ 1 - 1
docs/en/hot-reload.md

@@ -41,4 +41,4 @@ if (module.hot) {
 }
 }
 ```
 ```
 
 
-You don't need to do anything specific for actions and getters. Webpack's hot module replacement system will "bubble" changes up the dependency chain - and changes in actions and getters will bubble up to the Vue components that imported them. Because Vue components loaded via `vue-loader` are automatically hot-reloadable, these affected components will hot-reload themselves and use the updated actions and getters.
+Checkout the [counter-hot example](https://github.com/vuejs/vuex/tree/master/examples/counter-hot) to play with hot-reload.

+ 10 - 8
docs/en/plugins.md

@@ -7,9 +7,7 @@ const myPlugin = store => {
   // called when the store is initialized
   // called when the store is initialized
   store.subscribe((mutation, state) => {
   store.subscribe((mutation, state) => {
     // called after every mutation.
     // called after every mutation.
-    // The mutation comes in the format of { type, payload } for normal
-    // dispatches, and will be the original mutation object for object-style
-    // dispatches.
+    // The mutation comes in the format of { type, payload }.
   })
   })
 }
 }
 ```
 ```
@@ -23,17 +21,17 @@ const store = new Vuex.Store({
 })
 })
 ```
 ```
 
 
-### Dispatching Inside Plugins
+### Committing Mutations Inside Plugins
 
 
-Plugins are not allowed to directly mutate state - similar to your components, they can only trigger changes by dispatching mutations.
+Plugins are not allowed to directly mutate state - similar to your components, they can only trigger changes by committing mutations.
 
 
-By dispatching mutations, a plugin can be used to sync a data source to the store. For example, to sync a websocket data source to the store (this is just a contrived example, in reality the `createPlugin` function can take some additional options for more complex tasks):
+By committing mutations, a plugin can be used to sync a data source to the store. For example, to sync a websocket data source to the store (this is just a contrived example, in reality the `createPlugin` function can take some additional options for more complex tasks):
 
 
 ``` js
 ``` js
 export default function createWebSocketPlugin (socket) {
 export default function createWebSocketPlugin (socket) {
   return store => {
   return store => {
     socket.on('data', data => {
     socket.on('data', data => {
-      store.dispatch('RECEIVE_DATA', data)
+      store.commit('receiveData', data)
     })
     })
     store.subscribe(mutation => {
     store.subscribe(mutation => {
       if (mutation.type === 'UPDATE_DATA') {
       if (mutation.type === 'UPDATE_DATA') {
@@ -87,10 +85,12 @@ The plugin will be used by default. For production, you will need [DefinePlugin]
 
 
 ### Built-in Logger Plugin
 ### Built-in Logger Plugin
 
 
+> If you are using [vue-devtools](https://github.com/vuejs/vue-devtools) you probably don't need this.
+
 Vuex comes with a logger plugin for common debugging usage:
 Vuex comes with a logger plugin for common debugging usage:
 
 
 ``` js
 ``` js
-import createLogger from 'vuex/logger'
+import createLogger from 'vuex/dist/logger'
 
 
 const store = new Vuex.Store({
 const store = new Vuex.Store({
   plugins: [createLogger()]
   plugins: [createLogger()]
@@ -115,4 +115,6 @@ const logger = createLogger({
 })
 })
 ```
 ```
 
 
+The logger file can also be included directly via a `<script>` tag, and will expose the `createVuexLogger` function globally.
+
 Note the logger plugin takes state snapshots, so use it only during development.
 Note the logger plugin takes state snapshots, so use it only during development.

+ 12 - 116
docs/en/structure.md

@@ -2,41 +2,15 @@
 
 
 Vuex doesn't really restrict how you structure your code. Rather, it enforces a set of high-level principles:
 Vuex doesn't really restrict how you structure your code. Rather, it enforces a set of high-level principles:
 
 
-1. Application state is held in the store, as a single object.
+1. Application-level state is centralized in the store.
 
 
-2. The only way to mutate the state is by dispatching mutations on the store.
+2. The only way to mutate the state is by committing **mutations**, which are synchronous transactions.
 
 
-3. Mutations must be synchronous, and the only side effects they produce should be mutating the state.
+3. Asynchronous logic should be encapsulated in, and can be composed with **actions**.
 
 
-4. We can expose a more expressive state mutation API by defining actions. Actions can encapsulate asynchronous logic such as data fetching, and the only side effects they produce should be dispatching mutations.
+As long as you follow these rules, it's up to you how to structure your project. If your store file gets too big, simply start splitting the actions, mutations and getters into separate files.
 
 
-5. Components use getters to retrieve state from the store, and call actions to mutate the state.
-
-The nice thing about Vuex mutations, actions and getters is that **they are all just functions**. As long as you follow these rules, it's up to you how to structure your project. However, it's nice to have some conventions so that you can instantly become familiar with another project that uses Vuex, so here are some recommended structures depending on the scale of your app.
-
-### Simple Project
-
-For a simple project, we can simply define the **store** and the **actions** in respective files:
-
-``` bash
-.
-├── index.html
-├── main.js
-├── components
-│   ├── App.vue
-│   └── ...
-└── vuex
-    ├── store.js     # exports the store (with initial state and mutations)
-    └── actions.js   # exports all actions
-```
-
-For an actual example, check out the [Counter example](https://github.com/vuejs/vuex/tree/master/examples/counter) or the [TodoMVC example](https://github.com/vuejs/vuex/tree/master/examples/todomvc).
-
-Alternatively, you can also split out mutations into its own file.
-
-### Medium to Large Project
-
-For any non-trivial app, we probably want to further split Vuex-related code into multiple "modules" (roughly comparable to "stores" in vanilla Flux, and "reducers" in Redux), each dealing with a specific domain of our app. Each module would be managing a sub-tree of the state, exporting the initial state for that sub-tree and all mutations that operate on that sub-tree:
+For any non-trivial app, we will likely need to leverage modules. Here's an example project structure:
 
 
 ``` bash
 ``` bash
 ├── index.html
 ├── index.html
@@ -46,91 +20,13 @@ For any non-trivial app, we probably want to further split Vuex-related code int
 ├── components
 ├── components
 │   ├── App.vue
 │   ├── App.vue
 │   └── ...
 │   └── ...
-└── vuex
-    ├── actions.js        # exports all actions
-    ├── store.js          # where we assemble modules and export the store
-    ├── mutation-types.js # constants
+└── store
+    ├── index.js          # where we assemble modules and export the store
+    ├── actions.js        # root actions
+    ├── mutations.js      # root mutations
     └── modules
     └── modules
-        ├── cart.js       # state and mutations for cart
-        └── products.js   # state and mutations for products
-```
-
-A typical module looks like this:
-
-``` js
-// vuex/modules/products.js
-import {
-  RECEIVE_PRODUCTS,
-  ADD_TO_CART
-} from '../mutation-types'
-
-// initial state
-const state = {
-  all: []
-}
-
-// mutations
-const mutations = {
-  [RECEIVE_PRODUCTS] (state, products) {
-    state.all = products
-  },
-
-  [ADD_TO_CART] (state, productId) {
-    state.all.find(p => p.id === productId).inventory--
-  }
-}
-
-export default {
-  state,
-  mutations
-}
-```
-
-And in `vuex/store.js`, we "assemble" multiple modules together to create the Vuex instance:
-
-``` js
-// vuex/store.js
-import Vue from 'vue'
-import Vuex from '../../../src'
-// import parts from modules
-import cart from './modules/cart'
-import products from './modules/products'
-
-Vue.use(Vuex)
-
-export default new Vuex.Store({
-  // combine sub modules
-  modules: {
-    cart,
-    products
-  }
-})
+        ├── cart.js       # cart module
+        └── products.js   # products module
 ```
 ```
 
 
-Here, `cart` module's initial state will be attached to the root state tree as `store.state.cart`. In addition, **all the mutations defined in a sub-module only receive the sub-state-tree they are associated with**. So mutations defined in the `cart` module will receive `store.state.cart` as their first argument.
-
-The root of the sub-state-tree is irreplaceable inside the module itself. For example this won't work:
-
-``` js
-const mutations = {
-  SOME_MUTATION (state) {
-    state = { ... }
-  }
-}
-```
-
-Instead, always store actual state as a property of the sub-tree root:
-
-``` js
-const mutations = {
-  SOME_MUTATION (state) {
-    state.value = { ... }
-  }
-}
-```
-
-Since all modules simply export objects and functions, they are quite easy to test and maintain, and can be hot-reloaded. You are also free to alter the patterns used here to find a structure that fits your preference.
-
-Note that we do not put actions into modules, because a single action may dispatch mutations that affect multiple modules. It's also a good idea to decouple actions from the state shape and the implementation details of mutations for better separation of concerns. If the actions file gets too large, we can turn it into a folder and split out the implementations of long async actions into individual files.
-
-For an example, check out the [Shopping Cart Example](https://github.com/vuejs/vuex/tree/master/examples/shopping-cart).
+As a reference, check out the [Shopping Cart Example](https://github.com/vuejs/vuex/tree/master/examples/shopping-cart).

+ 16 - 14
docs/en/testing.md

@@ -22,7 +22,9 @@ Example testing a mutation using Mocha + Chai (you can use any framework/asserti
 
 
 ``` js
 ``` js
 // mutations.js
 // mutations.js
-export const INCREMENT = state => state.count++
+export const mutations = {
+  increment: state => state.count++
+}
 ```
 ```
 
 
 ``` js
 ``` js
@@ -31,14 +33,14 @@ import { expect } from 'chai'
 import { mutations } from './store'
 import { mutations } from './store'
 
 
 // destructure assign mutations
 // destructure assign mutations
-const { INCREMENT } = mutations
+const { increment } = mutations
 
 
 describe('mutations', () => {
 describe('mutations', () => {
   it('INCREMENT', () => {
   it('INCREMENT', () => {
     // mock state
     // mock state
     const state = { count: 0 }
     const state = { count: 0 }
     // apply mutation
     // apply mutation
-    INCREMENT(state)
+    increment(state)
     // assert result
     // assert result
     expect(state.count).to.equal(1)
     expect(state.count).to.equal(1)
   })
   })
@@ -86,10 +88,11 @@ const actions = actionsInjector({
 // helper for testing action with expected mutations
 // helper for testing action with expected mutations
 const testAction = (action, args, state, expectedMutations, done) => {
 const testAction = (action, args, state, expectedMutations, done) => {
   let count = 0
   let count = 0
-  // mock dispatch
-  const dispatch = (name, ...payload) => {
+
+  // mock commit
+  const commit = (type, payload) => {
     const mutation = expectedMutations[count]
     const mutation = expectedMutations[count]
-    expect(mutation.name).to.equal(name)
+    expect(mutation.type).to.equal(type)
     if (payload) {
     if (payload) {
       expect(mutation.payload).to.deep.equal(payload)
       expect(mutation.payload).to.deep.equal(payload)
     }
     }
@@ -98,8 +101,9 @@ const testAction = (action, args, state, expectedMutations, done) => {
       done()
       done()
     }
     }
   }
   }
+
   // call the action with mocked store and arguments
   // call the action with mocked store and arguments
-  action({dispatch, state}, ...args)
+  action({ commit, state }, ...args)
 
 
   // check if no mutations should have been dispatched
   // check if no mutations should have been dispatched
   if (expectedMutations.length === 0) {
   if (expectedMutations.length === 0) {
@@ -111,8 +115,8 @@ const testAction = (action, args, state, expectedMutations, done) => {
 describe('actions', () => {
 describe('actions', () => {
   it('getAllProducts', done => {
   it('getAllProducts', done => {
     testAction(actions.getAllProducts, [], {}, [
     testAction(actions.getAllProducts, [], {}, [
-      { name: 'REQUEST_PRODUCTS' },
-      { name: 'RECEIVE_PRODUCTS', payload: [ /* mocked response */ ] }
+      { type: 'REQUEST_PRODUCTS' },
+      { type: 'RECEIVE_PRODUCTS', payload: { /* mocked response */ } }
     ], done)
     ], done)
   })
   })
 })
 })
@@ -124,9 +128,10 @@ If your mutations and actions are written properly, the tests should have no dir
 
 
 #### Running in Node
 #### Running in Node
 
 
-Create the following webpack config:
+Create the following webpack config (together with proper [`.babelrc`](https://babeljs.io/docs/usage/babelrc/)):
 
 
 ``` js
 ``` js
+// webpack.config.js
 module.exports = {
 module.exports = {
   entry: './test.js',
   entry: './test.js',
   output: {
   output: {
@@ -141,9 +146,6 @@ module.exports = {
         exclude: /node_modules/
         exclude: /node_modules/
       }
       }
     ]
     ]
-  },
-  babel: {
-    presets: ['es2015']
   }
   }
 }
 }
 ```
 ```
@@ -164,4 +166,4 @@ mocha test-bundle.js
 
 
 #### Running in Browser with Karma + karma-webpack
 #### Running in Browser with Karma + karma-webpack
 
 
-Consult the setup in [vue-loader documentation](http://vuejs.github.io/vue-loader/workflow/testing.html).
+Consult the setup in [vue-loader documentation](http://vue-loader.vuejs.org/en/workflow/testing.html).