Browse Source

more docs wip

Evan You 9 năm trước cách đây
mục cha
commit
b4addcd6f0

+ 11 - 1
docs/book.json

@@ -1,3 +1,13 @@
 {
 {
-  "gitbook": "2.6.2"
+  "gitbook": "2.x.x",
+  "plugins": ["edit-link", "prism", "-highlight", "github"],
+  "pluginsConfig": {
+    "edit-link": {
+      "base": "https://github.com/vuejs/vuex/tree/master/docs",
+      "label": "Edit This Page"
+    },
+    "github": {
+      "url": "https://github.com/vuejs/vuex/"
+    }
+  }
 }
 }

+ 0 - 13
docs/en/README.md

@@ -1,13 +0,0 @@
-## What is Vuex?
-
-Vuex is an application architecture for centralized state management in Vue.js applications. It is inspired by [Flux](https://facebook.github.io/flux/) and [Redux](https://github.com/rackt/redux), but with simplified concepts and an implementation that is designed specifically to take advantage of Vue.js' reactivity system.
-
-## Why do I need this?
-
-If your app is simple enough, you probably don't need Vuex. Don't apply it prematurely. But if you are building a medium-to-large-scale SPA, chances are you have run into situations that make you think about how to better structure things outside of your Vue components. This is where Vuex comes into play.
-
-When using Vue.js alone, we often tend to store the state "inside" our components. That is, each component owns a piece of our application state, and as a result the state is scattered all over the place. However, sometimes a piece of state needs to be shared by multiple components. A commonly-seen practice is letting one component "send" some state to other components using the custom event system. However, the event flow inside large component trees can quickly become complex, and it's often difficult to reason about when something goes wrong.
-
-To better deal with shared state in large applications, we need to differentiate between **component local state** and **application level state**. Application state does not belong to a specific component, but our components can still observe it for reactive DOM updates. By centralizing its management in a single place, we no longer need to pass events around, because everything that affects more than one component should belong there. In addition, this allows us to record and inspect every mutation for easier understanding of state changes, and even implement fancy stuff like time-travel debugging.
-
-Vuex also enforces some opinions on how to split state management logic into different places, but still allows enough flexibility for the actual code structure.

+ 1 - 0
docs/en/README.md

@@ -0,0 +1 @@
+SUMMARY.md

+ 3 - 0
docs/en/SUMMARY.md

@@ -1,3 +1,6 @@
+# Table of Contents
+
+- [What is Vuex?](intro.md)
 - [Core Concepts](concepts.md)
 - [Core Concepts](concepts.md)
   - [State](state.md)
   - [State](state.md)
   - [Mutations](mutations.md)
   - [Mutations](mutations.md)

+ 122 - 0
docs/en/actions.md

@@ -0,0 +1,122 @@
+# Actions
+
+Actions are functions that dispatch mutations. Actions can be asynchronous and a single action can dispatch multiple mutations.
+
+An action expresses the intention for something to happen, and abstracts the details away from the component calling it. When a component wants to do something, it just calls an action - there's no need to worry about a callback or a return value, because actions result in state changes, and state changes will trigger the component's DOM to update - the component is completely decoupled from how that action is actually performed.
+
+> Vuex actions are in fact "action creators" in vanilla flux definitions, but I find that term more confusing than useful.
+
+### Simple Actions
+
+It is common that an action simply triggers a single mutation. Vuex provides a shorthand for defining such actions:
+
+``` js
+const vuex = new Vuex({
+  state: {
+    count: 1
+  },
+  mutations: {
+    INCREMENT (state, x) {
+      state += x
+    }
+  },
+  actions: {
+    // shorthand
+    // just provide the mutation name.
+    increment: 'INCREMENT'
+  }
+})
+```
+
+Now when we call the action:
+
+``` js
+vuex.actions.increment(1)
+```
+
+It simply calls the following for us:
+
+``` js
+vuex.dispatch('INCREMENT', 1)
+```
+
+Note any arguments passed to the action is also passed along to the mutation handler.
+
+### Thunk Actions
+
+How about actions that involve logic depending on current state, or that need async operations? We can define these actions as **thunks** - essentially functions that return another function:
+
+``` js
+const vuex = new Vuex({
+  state: {
+    count: 1
+  },
+  mutations: {
+    INCREMENT (state, x) {
+      state += x
+    }
+  },
+  actions: {
+    incrementIfOdd: function (x) {
+      return function (dispatch, state) {
+        if ((state.count + 1) % 2 === 0) {
+          dispatch('INCREMENT', x)
+        }
+      }
+    }
+  }
+})
+```
+
+Here, the outer function receives the arguments passed when calling the action. Then, it returns a function that gets 2 arguments: first is the `dispatch` function, and the second being the `state`. We are using ES5 syntax here to make things easier to understand. With ES2015 arrow functions we can "prettify" the above to the following:
+
+``` js
+// ...
+actions: {
+  incrementIfOdd: x => (dispatch, state) => {
+    if ((state.count + 1) % 2 === 0) {
+      dispatch('INCREMENT', x)
+    }
+  }
+}
+```
+
+### Async Actions
+
+We can use the same thunk syntax for defining async actions:
+
+``` js
+// ...
+actions: {
+  incrementAsync: x => dispatch => {
+    setTimeout(() => {
+      dispatch('INCREMENT', x)
+    }, 1000)
+  }
+}
+```
+
+A more practical example is when checking out a shopping cart - we may need to trigger multiple mutations: one that signifies the checkout has started, one for success, and one for failure:
+
+``` js
+// ...
+actions: {
+  checkout: products => (dispatch, state) => {
+    // save the current in cart items
+    const savedCartItems = [...state.cart.added]
+    // send out checkout request, and optimistically
+    // clear the cart
+    dispatch(types.CHECKOUT_REQUEST)
+    // the shop API accepts a success callback and a failure callback
+    shop.buyProducts(
+      products,
+      // handle success
+      () => dispatch(types.CHECKOUT_SUCCESS),
+      // handle failure
+      () => dispatch(types.CHECKOUT_FAILURE, savedCartItems)
+    )
+  }
+}
+```
+
+Again, all the component needs to do to perform the entire checkout is just calling `vuex.actions,checkout(products)`.

+ 1 - 0
docs/en/book.json

@@ -0,0 +1 @@
+../book.json

+ 4 - 2
docs/en/concepts.md

@@ -1,4 +1,4 @@
-## Core Concepts
+# Core Concepts
 
 
 Similar to Vue itself, Vuex exposes a single `Vuex` constructor. You can use it to create **Vuex instances**. In most cases, you only need one Vuex instance for an app. You can think of a Vuex instance as an "enhanced store" that holds your app state.
 Similar to Vue itself, Vuex exposes a single `Vuex` constructor. You can use it to create **Vuex instances**. In most cases, you only need one Vuex instance for an app. You can think of a Vuex instance as an "enhanced store" that holds your app state.
 
 
@@ -14,11 +14,13 @@ Why do we have mutations and actions, rather then just simple functions that man
 
 
 > If you are familiar with Flux, note there's a term/concept difference here: Vuex mutations are the equivalent of Flux *actions*, while Vuex actions are equivalent to Flux *action creators*.
 > If you are familiar with Flux, note there's a term/concept difference here: Vuex mutations are the equivalent of Flux *actions*, while Vuex actions are equivalent to Flux *action creators*.
 
 
-### Putting it Together
+### Creating a Vuex Instance
 
 
 Creating a Vuex instance is pretty straightforward - just put the aforementioned ingredients together:
 Creating a Vuex instance is pretty straightforward - just put the aforementioned ingredients together:
 
 
 ``` js
 ``` js
+import Vuex from 'vuex'
+
 const vuex = new Vuex({
 const vuex = new Vuex({
   state: { ... },
   state: { ... },
   actions: { ... },
   actions: { ... },

+ 13 - 0
docs/en/intro.md

@@ -0,0 +1,13 @@
+## What is Vuex?
+
+Vuex is an application architecture for centralized state management in Vue.js applications. It is inspired by [Flux](https://facebook.github.io/flux/) and [Redux](https://github.com/rackt/redux), but with simplified concepts and an implementation that is designed specifically to take advantage of Vue.js' reactivity system.
+
+## Why do I need this?
+
+If your app is simple enough, you probably don't need Vuex. Don't apply it prematurely. But if you are building a medium-to-large-scale SPA, chances are you have run into situations that make you think about how to better structure things outside of your Vue components. This is where Vuex comes into play.
+
+When using Vue.js alone, we often tend to store the state "inside" our components. That is, each component owns a piece of our application state, and as a result the state is scattered all over the place. However, sometimes a piece of state needs to be shared by multiple components. A commonly-seen practice is letting one component "send" some state to other components using the custom event system. However, the event flow inside large component trees can quickly become complex, and it's often difficult to reason about when something goes wrong.
+
+To better deal with shared state in large applications, we need to differentiate between **component local state** and **application level state**. Application state does not belong to a specific component, but our components can still observe it for reactive DOM updates. By centralizing its management in a single place, we no longer need to pass events around, because everything that affects more than one component should belong there. In addition, this allows us to record and inspect every mutation for easier understanding of state changes, and even implement fancy stuff like time-travel debugging.
+
+Vuex also enforces some opinions on how to split state management logic into different places, but still allows enough flexibility for the actual code structure.

+ 80 - 0
docs/en/mutations.md

@@ -0,0 +1,80 @@
+# Mutations
+
+Vuex mutations are essentially events: each mutation has a **name** and a **handler**. The handler function always gets the entire state tree as the first argument:
+
+``` js
+import Vuex from 'vuex'
+
+const vuex = new Vuex({
+  state: {
+    count: 1
+  },
+  mutations: {
+    INCREMENT (state) {
+      // mutate state
+      state.count++
+    }
+  }
+})
+```
+
+Using all caps for mutation names is just a convention to make it easier to differentiate them from actions.
+
+You cannot directly call a mutation handler. The options here is more like event registration: "When an `INCREMENT` event is dispatched, call this handler." To invoke a mutation handler, you need to dispatch a mutation event:
+
+``` js
+vuex.dispatch('INCREMENT')
+```
+
+### Dispatch with Arguments
+
+It is also possible to pass along arguments:
+
+``` js
+// ...
+mutations: {
+  INCREMENT (state, n) {
+    state.count += n
+  }
+}
+```
+``` js
+vuex.dispatch('INCREMENT', 10)
+```
+
+Here `10` will be passed to the mutation handler as the second argument following `state`. Same for any additional arguments. These arguments are called the **payload** for the given mutation.
+
+### Using Constants for Mutation Names
+
+It is also common to use constants for mutation names - they allow the code to take advantage of tooling like linters, and putting all constants in a single file allows your collaborators to get an at-a-glance view of what mutations are possible in the entire application:
+
+``` js
+// mutation-types.js
+export const SOME_MUTATION = 'SOME_MUTATION'
+```
+
+``` js
+// vuex.js
+import Vuex from 'vuex'
+import { SOME_MUTATION } from './mutation-types'
+
+const vuex = new Vuex({
+  state: { ... },
+  actiosn: { ... },
+  mutations: {
+    // we can use the ES2015 computed property name feature
+    // to use a constant as the function name
+    [SOME_MUTATION] (state) {
+      // mutate state
+    }
+  }
+})
+```
+
+Whether to use constants is largely a preference - it can be helpful in large projects with many developers, but it's totally optional if you don't like them.
+
+### On to Actions
+
+Manually calling `vuex.dispatch` is possible, but in practice, we will rarely do this in our component code. Most of the time we will be calling [actions](actions.md), which can encapsulate more complex logic such as async data fetching.
+
+Also, one important rule to remember: all mutation handlers must be **synchronous**. Any async operations belong in actions.

+ 3 - 3
docs/en/state.md

@@ -1,4 +1,4 @@
-## State
+# State
 
 
 ### Single State Tree
 ### Single State Tree
 
 
@@ -41,8 +41,8 @@ export default {
 
 
 Because the `data` function does not track any reactive dependencies, we are only getting a static reference to `vuex.state.message`. When the Vuex state is mutated later, the component has no idea that something has changed. In comparison, computed properties track all reactive dependencies when they are evaluated, so they reactively re-evaluate when the related vuex state mutates.
 Because the `data` function does not track any reactive dependencies, we are only getting a static reference to `vuex.state.message`. When the Vuex state is mutated later, the component has no idea that something has changed. In comparison, computed properties track all reactive dependencies when they are evaluated, so they reactively re-evaluate when the related vuex state mutates.
 
 
-### State Can Only Be Mutated by Vuex Mutations
+### Components Are Not Allowed to Directly Mutate State
 
 
 Using read-only computed properties has another benefit in that it helps emphasizing the rule that **components should never directly mutate Vuex state**. Because we want every state mutation to be explicit and trackable, all vuex state mutations must be conducted inside vuex mutation handlers.
 Using read-only computed properties has another benefit in that it helps emphasizing the rule that **components should never directly mutate Vuex state**. Because we want every state mutation to be explicit and trackable, all vuex state mutations must be conducted inside vuex mutation handlers.
 
 
-So essentially, our Vue components now becomes very thin: they connect to Vuex state via read-only computed properties, and the only way for them to affect Vuex state is by calling **actions**, which in turn trigger **mutations**. They can still possess and operate on their local state if necessary, but we no longer put any data-fetching or global-state-mutating logic inside individual components.
+With this rule enforced, our Vue components now hold a lot less responsibility: they connect to Vuex state via read-only computed properties, and the only way for them to affect Vuex state is by calling **actions**, which in turn trigger **mutations**. They can still possess and operate on their local state if necessary, but we no longer put any data-fetching or global-state-mutating logic inside individual components.