From a9abce0dbcd09cb1ecb07a5c1aa6a70085c28eab Mon Sep 17 00:00:00 2001 From: ChangJoo Park Date: Sun, 11 Dec 2016 09:33:44 +0900 Subject: [PATCH 01/20] Add Korean directory --- docs/ko/README.md | 1 + docs/ko/SUMMARY.md | 22 ++++ docs/ko/actions.md | 175 ++++++++++++++++++++++++++++++ docs/ko/api.md | 177 ++++++++++++++++++++++++++++++ docs/ko/book.json | 19 ++++ docs/ko/forms.md | 58 ++++++++++ docs/ko/getters.md | 91 ++++++++++++++++ docs/ko/getting-started.md | 44 ++++++++ docs/ko/hot-reload.md | 44 ++++++++ docs/ko/images/flow.png | Bin 0 -> 69033 bytes docs/ko/images/vuex.png | Bin 0 -> 21959 bytes docs/ko/installation.md | 51 +++++++++ docs/ko/intro.md | 63 +++++++++++ docs/ko/modules.md | 138 ++++++++++++++++++++++++ docs/ko/mutations.md | 186 ++++++++++++++++++++++++++++++++ docs/ko/plugins.md | 120 +++++++++++++++++++++ docs/ko/state.md | 109 +++++++++++++++++++ docs/ko/strict.md | 25 +++++ docs/ko/structure.md | 32 ++++++ docs/ko/testing.md | 216 +++++++++++++++++++++++++++++++++++++ 20 files changed, 1571 insertions(+) create mode 100644 docs/ko/README.md create mode 100644 docs/ko/SUMMARY.md create mode 100644 docs/ko/actions.md create mode 100644 docs/ko/api.md create mode 100644 docs/ko/book.json create mode 100644 docs/ko/forms.md create mode 100644 docs/ko/getters.md create mode 100644 docs/ko/getting-started.md create mode 100644 docs/ko/hot-reload.md create mode 100644 docs/ko/images/flow.png create mode 100644 docs/ko/images/vuex.png create mode 100644 docs/ko/installation.md create mode 100644 docs/ko/intro.md create mode 100644 docs/ko/modules.md create mode 100644 docs/ko/mutations.md create mode 100644 docs/ko/plugins.md create mode 100644 docs/ko/state.md create mode 100644 docs/ko/strict.md create mode 100644 docs/ko/structure.md create mode 100644 docs/ko/testing.md diff --git a/docs/ko/README.md b/docs/ko/README.md new file mode 100644 index 000000000..f8a898044 --- /dev/null +++ b/docs/ko/README.md @@ -0,0 +1 @@ +{% include "./SUMMARY.md" %} diff --git a/docs/ko/SUMMARY.md b/docs/ko/SUMMARY.md new file mode 100644 index 000000000..1dcc212d0 --- /dev/null +++ b/docs/ko/SUMMARY.md @@ -0,0 +1,22 @@ +# Vuex + +> Note: This is docs for vuex@2.x. + +- [Looking for 1.0 Docs?](https://github.com/vuejs/vuex/tree/1.0/docs) +- [Release Notes](https://github.com/vuejs/vuex/releases) +- [Installation](installation.md) +- [What is Vuex?](intro.md) +- [Getting Started](getting-started.md) +- Core Concepts + - [State](state.md) + - [Getters](getters.md) + - [Mutations](mutations.md) + - [Actions](actions.md) + - [Modules](modules.md) +- [Application Structure](structure.md) +- [Plugins](plugins.md) +- [Strict Mode](strict.md) +- [Form Handling](forms.md) +- [Testing](testing.md) +- [Hot Reloading](hot-reload.md) +- [API Reference](api.md) diff --git a/docs/ko/actions.md b/docs/ko/actions.md new file mode 100644 index 000000000..f590cd785 --- /dev/null +++ b/docs/ko/actions.md @@ -0,0 +1,175 @@ +# Actions + +Actions are similar to mutations, the difference being that: + +- Instead of mutating the state, actions commit mutations. +- Actions can contain arbitrary asynchronous operations. + +Let's register a simple action: + +``` js +const store = new Vuex.Store({ + state: { + count: 0 + }, + mutations: { + increment (state) { + state.count++ + } + }, + actions: { + increment (context) { + context.commit('increment') + } + } +}) +``` + +Action handlers receive a context object which exposes the same set of methods/properties on the store instance, so you can call `context.commit` to commit a mutation, or access the state and getters via `context.state` and `context.getters`. We will see why this context object is not the store instance itself when we introduce [Modules](modules.md) later. + +In practice, we often use ES2015 [argument destructuring](https://github.com/lukehoban/es6features#destructuring) to simplify the code a bit (especially when we need to call `commit` multiple times): + +``` js +actions: { + increment ({ commit }) { + commit('increment') + } +} +``` + +### Dispatching Actions + +Actions are triggered with the `store.dispatch` method: + +``` js +store.dispatch('increment') +``` + +This may look dumb at first sight: if we want to increment the count, why don't we just call `store.commit('increment')` directly? Well, remember that **mutations must be synchronous**? Actions don't. We can perform **asynchronous** operations inside an action: + +``` js +actions: { + incrementAsync ({ commit }) { + setTimeout(() => { + commit('increment') + }, 1000) + } +} +``` + +Actions support the same payload format and object-style dispatch: + +``` js +// dispatch with a payload +store.dispatch('incrementAsync', { + amount: 10 +}) + +// dispatch with an object +store.dispatch({ + type: 'incrementAsync', + amount: 10 +}) +``` + +A more practical example of real-world actions would be an action to checkout a shopping cart, which involves **calling an async API** and **committing multiple mutations**: + +``` js +actions: { + checkout ({ commit, state }, products) { + // save the items currently in the cart + const savedCartItems = [...state.cart.added] + // send out checkout request, and optimistically + // clear the cart + commit(types.CHECKOUT_REQUEST) + // the shop API accepts a success callback and a failure callback + shop.buyProducts( + products, + // handle success + () => commit(types.CHECKOUT_SUCCESS), + // handle failure + () => commit(types.CHECKOUT_FAILURE, savedCartItems) + ) + } +} +``` + +Note we are performing a flow of asynchronous operations, and recording the side effects (state mutations) of the action by committing them. + +### Dispatching Actions in Components + +You can dispatch actions in components with `this.$store.dispatch('xxx')`, or use the `mapActions` helper which maps component methods to `store.dispatch` calls (requires root `store` injection): + +``` js +import { mapActions } from 'vuex' + +export default { + // ... + methods: { + ...mapActions([ + 'increment' // map this.increment() to this.$store.dispatch('increment') + ]), + ...mapActions({ + add: 'increment' // map this.add() to this.$store.dispatch('increment') + }) + } +} +``` + +### Composing Actions + +Actions are often asynchronous, so how do we know when an action is done? And more importantly, how can we compose multiple actions together to handle more complex async flows? + +The first thing to know is that `store.dispatch` can handle Promise returned by the triggered action handler and it also returns Promise: + +``` js +actions: { + actionA ({ commit }) { + return new Promise((resolve, reject) => { + setTimeout(() => { + commit('someMutation') + resolve() + }, 1000) + }) + } +} +``` + +Now you can do: + +``` js +store.dispatch('actionA').then(() => { + // ... +}) +``` + +And also in another action: + +``` js +actions: { + // ... + actionB ({ dispatch, commit }) { + return dispatch('actionA').then(() => { + commit('someOtherMutation') + }) + } +} +``` + +Finally, if we make use of [async / await](https://tc39.github.io/ecmascript-asyncawait/), a JavaScript feature landing very soon, we can compose our actions like this: + +``` js +// assuming getData() and getOtherData() return Promises + +actions: { + async actionA ({ commit }) { + commit('gotData', await getData()) + }, + async actionB ({ dispatch, commit }) { + await dispatch('actionA') // wait for actionA to finish + commit('gotOtherData', await getOtherData()) + } +} +``` + +> It's possible for a `store.dispatch` to trigger multiple action handlers in different modules. In such a case the returned value will be a Promise that resolves when all triggered handlers have been resolved. diff --git a/docs/ko/api.md b/docs/ko/api.md new file mode 100644 index 000000000..428980f73 --- /dev/null +++ b/docs/ko/api.md @@ -0,0 +1,177 @@ +# API Reference + +### Vuex.Store + +``` js +import Vuex from 'vuex' + +const store = new Vuex.Store({ ...options }) +``` + +### Vuex.Store Constructor Options + +- **state** + + - type: `Object` + + The root state object for the Vuex store. + + [Details](state.md) + +- **mutations** + + - type: `{ [type: string]: Function }` + + Register mutations on the store. The handler function always receives `state` as the first argument (will be module local state if defined in a module), and receives a second `payload` argument if there is one. + + [Details](mutations.md) + +- **actions** + + - type: `{ [type: string]: Function }` + + Register actions on the store. The handler function receives a `context` object that exposes the following properties: + + ``` js + { + state, // same as store.state, or local state if in modules + rootState, // same as store.state, only in modules + commit, // same as store.commit + dispatch, // same as store.dispatch + getters // same as store.getters + } + ``` + + [Details](actions.md) + +- **getters** + + - type: `{ [key: string]: Function }` + + Register getters on the store. The getter function receives the following arguments: + + ``` + state, // will be module local state if defined in a module. + getters, // same as store.getters + rootState // same as store.state + ``` + Registered getters are exposed on `store.getters`. + + [Details](getters.md) + +- **modules** + + - type: `Object` + + An object containing sub modules to be merged into the store, in the shape of: + + ``` js + { + key: { + state, + mutations, + actions?, + getters?, + modules? + }, + ... + } + ``` + + Each module can contain `state` and `mutations` similar to the root options. A module's state will be attached to the store's root state using the module's key. A module's mutations and getters will only receives the module's local state as the first argument instead of the root state, and module actions' `context.state` will also point to the local state. + + [Details](modules.md) + +- **plugins** + + - type: `Array` + + An array of plugin functions to be applied to the store. The plugin simply receives the store as the only argument and can either listen to mutations (for outbound data persistence, logging, or debugging) or dispatch mutations (for inbound data e.g. websockets or observables). + + [Details](plugins.md) + +- **strict** + + - type: `Boolean` + - default: `false` + + Force the Vuex store into strict mode. In strict mode any mutations to Vuex state outside of mutation handlers will throw an Error. + + [Details](strict.md) + +### Vuex.Store Instance Properties + +- **state** + + - type: `Object` + + The root state. Read only. + +- **getters** + + - type: `Object` + + Exposes registered getters. Read only. + +### Vuex.Store Instance Methods + +- **`commit(type: string, payload?: any) | commit(mutation: Object)`** + + Commit a mutation. [Details](mutations.md) + +- **`dispatch(type: string, payload?: any) | dispatch(action: Object)`** + + Dispatch an action. Returns a Promise that resolves all triggered action handlers. [Details](actions.md) + +- **`replaceState(state: Object)`** + + Replace the store's root state. Use this only for state hydration / time-travel purposes. + +- **`watch(getter: Function, cb: Function, options?: Object)`** + + Reactively watch a getter function's return value, and call the callback when the value changes. The getter receives the store's state as the only argument. Accepts an optional options object that takes the same options as Vue's `vm.$watch` method. + + To stop watching, call the returned handle function. + +- **`subscribe(handler: Function)`** + + Subscribe to store mutations. The `handler` is called after every mutation and receives the mutation descriptor and post-mutation state as arguments: + + ``` js + store.subscribe((mutation, state) => { + console.log(mutation.type) + console.log(mutation.payload) + }) + ``` + + Most commonly used in plugins. [Details](plugins.md) + +- **`registerModule(path: string | Array, module: Module)`** + + Register a dynamic module. [Details](modules.md#dynamic-module-registration) + +- **`unregisterModule(path: string | Array)`** + + Unregister a dynamic module. [Details](modules.md#dynamic-module-registration) + +- **`hotUpdate(newOptions: Object)`** + + Hot swap new actions and mutations. [Details](hot-reload.md) + +### Component Binding Helpers + +- **`mapState(map: Array | Object): Object`** + + Create component computed options that return the sub tree of the Vuex store. [Details](state.md#the-mapstate-helper) + +- **`mapGetters(map: Array | Object): Object`** + + Create component computed options that return the evaluated value of a getter. [Details](getters.md#the-mapgetters-helper) + +- **`mapActions(map: Array | Object): Object`** + + Create component methods options that dispatch an action. [Details](actions.md#dispatching-actions-in-components) + +- **`mapMutations(map: Array | Object): Object`** + + Create component methods options that commit a mutation. [Details](mutations.md#commiting-mutations-in-components) diff --git a/docs/ko/book.json b/docs/ko/book.json new file mode 100644 index 000000000..6e622745c --- /dev/null +++ b/docs/ko/book.json @@ -0,0 +1,19 @@ +{ + "gitbook": "2.x.x", + "plugins": ["edit-link", "prism", "-highlight", "github"], + "pluginsConfig": { + "edit-link": { + "base": "https://github.com/vuejs/vuex/tree/dev/docs", + "label": "Edit This Page" + }, + "github": { + "url": "https://github.com/vuejs/vuex/" + } + }, + "links": { + "sharing": { + "facebook": false, + "twitter": false + } + } +} diff --git a/docs/ko/forms.md b/docs/ko/forms.md new file mode 100644 index 000000000..219c6377d --- /dev/null +++ b/docs/ko/forms.md @@ -0,0 +1,58 @@ +# Form Handling + +When using Vuex in strict mode, it could be a bit tricky to use `v-model` on a piece of state that belongs to Vuex: + +``` html + +``` + +Assuming `obj` is a computed property that returns an Object from the store, the `v-model` here will attempt to directly mutate `obj.message` when the user types in the input. In strict mode, this will result in an error because the mutation is not performed inside an explicit Vuex mutation handler. + +The "Vuex way" to deal with it is binding the ``'s value and call an action on the `input` or `change` event: + +``` html + +``` +``` js +// ... +computed: { + ...mapState({ + message: state => state.obj.message + }) +}, +methods: { + updateMessage (e) { + this.$store.commit('updateMessage', e.target.value) + } +} +``` + +And here's the mutation handler: + +``` js +// ... +mutations: { + updateMessage (state, message) { + state.obj.message = message + } +} +``` + +### Two-way Computed Property + +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: + +``` js +// ... +computed: { + message: { + get () { + return this.$store.state.obj.message + }, + set (value) { + this.$store.commit('updateMessage', value) + } + } +} +``` + diff --git a/docs/ko/getters.md b/docs/ko/getters.md new file mode 100644 index 000000000..b4ab7941e --- /dev/null +++ b/docs/ko/getters.md @@ -0,0 +1,91 @@ +# Getters + +Sometimes we may need to compute derived state based on store state, for example filtering through a list of items and counting them: + +``` js +computed: { + doneTodosCount () { + return this.$store.state.todos.filter(todo => todo.done).length + } +} +``` + +If more than one component needs to make use of this, we have to either duplicate the function, or extract it into a shared helper and import it in multiple places - both are less than ideal. + +Vuex allows us to define "getters" in the store (think of them as computed properties for stores). Getters will receive the state as their 1st argument: + +``` js +const store = new Vuex.Store({ + state: { + todos: [ + { id: 1, text: '...', done: true }, + { id: 2, text: '...', done: false } + ] + }, + getters: { + doneTodos: state => { + return state.todos.filter(todo => todo.done) + } + } +}) +``` + +The getters will be exposed on the `store.getters` object: + +``` js +store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }] +``` + +Getters will also receive other getters as the 2nd argument: + +``` js +getters: { + // ... + doneTodosCount: (state, getters) => { + return getters.doneTodos.length + } +} +``` + +``` js +store.getters.doneTodosCount // -> 1 +``` + +We can now easily make use of it inside any component: + +``` js +computed: { + doneTodosCount () { + return this.$store.getters.doneTodosCount + } +} +``` + +### The `mapGetters` Helper + +The `mapGetters` helper simply maps store getters to local computed properties: + +``` js +import { mapGetters } from 'vuex' + +export default { + // ... + computed: { + // mix the getters into computed with object spread operator + ...mapGetters([ + 'doneTodosCount', + 'anotherGetter', + // ... + ]) + } +} +``` + +If you want to map a getter to a different name, use an object: + +``` js +...mapGetters({ + // map this.doneCount to store.getters.doneTodosCount + doneCount: 'doneTodosCount' +}) +``` diff --git a/docs/ko/getting-started.md b/docs/ko/getting-started.md new file mode 100644 index 000000000..4f937a465 --- /dev/null +++ b/docs/ko/getting-started.md @@ -0,0 +1,44 @@ +# Getting Started + +At the center of every Vuex application is the **store**. A "store" is basically a container that holds your application **state**. There are two things that makes a Vuex store different from a plain global object: + +1. Vuex stores are reactive. When Vue components retrieve state from it, they will reactively and efficiently update if the store's state changes. + +2. You cannot directly mutate the store's state. The only way to change a store's state is by explicitly **committing mutations**. This ensures every state change leaves a track-able record, and enables tooling that helps us better understand our applications. + +### The Simplest Store + +> **NOTE:** We will be using ES2015 syntax for code examples for the rest of the docs. If you haven't picked it up, [you should](https://babeljs.io/docs/learn-es2015/)! + +After [installing](installation.md) Vuex, let's create a store. It is pretty straightforward - just provide an initial state object, and some mutations: + +``` js +// Make sure to call Vue.use(Vuex) first if using a module system + +const store = new Vuex.Store({ + state: { + count: 0 + }, + mutations: { + increment (state) { + state.count++ + } + } +}) +``` + +Now, you can access the state object as `store.state`, and trigger a state change with the `store.commit` method: + +``` js +store.commit('increment') + +console.log(store.state.count) // -> 1 +``` + +Again, the reason we are committing a mutation instead of changing `store.state.count` directly, is because we want to explicitly track it. This simple convention makes your intention more explicit, so that you can reason about state changes in your app better when reading the code. In addition, this gives us the opportunity to implement tools that can log every mutation, take state snapshots, or even perform time travel debugging. + +Using store state in a component simply involves returning the state within a computed property, because the store state is reactive. Triggering changes simply means committing mutations in component methods. + +Here's an example of the [most basic Vuex counter app](https://jsfiddle.net/yyx990803/n9jmu5v7/). + +Next, we will discuss each core concept in much finer details, starting with [State](state.md). diff --git a/docs/ko/hot-reload.md b/docs/ko/hot-reload.md new file mode 100644 index 000000000..8a3e72f27 --- /dev/null +++ b/docs/ko/hot-reload.md @@ -0,0 +1,44 @@ +# Hot Reloading + +Vuex supports hot-reloading mutations, modules, actions and getters during development, using Webpack's [Hot Module Replacement API](https://webpack.github.io/docs/hot-module-replacement.html). You can also use it in Browserify with the [browserify-hmr](https://github.com/AgentME/browserify-hmr/) plugin. + +For mutations and modules, you need to use the `store.hotUpdate()` API method: + +``` js +// store.js +import Vue from 'vue' +import Vuex from 'vuex' +import mutations from './mutations' +import moduleA from './modules/a' + +Vue.use(Vuex) + +const state = { ... } + +const store = new Vuex.Store({ + state, + mutations, + modules: { + a: moduleA + } +}) + +if (module.hot) { + // accept actions and mutations as hot modules + module.hot.accept(['./mutations', './modules/a'], () => { + // require the updated modules + // have to add .default here due to babel 6 module output + const newMutations = require('./mutations').default + const newModuleA = require('./modules/a').default + // swap in the new actions and mutations + store.hotUpdate({ + mutations: newMutations, + modules: { + a: newModuleA + } + }) + }) +} +``` + +Checkout the [counter-hot example](https://github.com/vuejs/vuex/tree/dev/examples/counter-hot) to play with hot-reload. diff --git a/docs/ko/images/flow.png b/docs/ko/images/flow.png new file mode 100644 index 0000000000000000000000000000000000000000..fd9b97d5947829d9a4ba6d1869b6f4c91b48f767 GIT binary patch literal 69033 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 EUl}O2b^rhX literal 0 HcmV?d00001 diff --git a/docs/ko/images/vuex.png b/docs/ko/images/vuex.png new file mode 100644 index 0000000000000000000000000000000000000000..0181299473acaed53c88ae6f38deb086eea824b7 GIT binary patch literal 21959 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 +[Unpkg.com](https://unpkg.com) provides NPM-based CDN links. The above link will always point to the latest release on NPM. You can also use a specific version/tag via URLs like `https://unpkg.com/vuex@2.0.0`. + + +Include `vuex` after Vue and it will install itself automatically: + +``` html + + +``` + +### NPM + +``` bash +npm install vuex +``` + +### Yarn + +``` bash +yarn add vuex +``` + +When used with a module system, you must explicitly install Vuex via `Vue.use()`: + +``` js +import Vue from 'vue' +import Vuex from 'vuex' + +Vue.use(Vuex) +``` + +You don't need to do this when using global script tags. + +### Dev Build + +You will have to clone directly from GitHub and build `vuex` yourself if +you want to use the latest dev build. + +``` bash +git clone https://github.com/vuejs/vuex.git node_modules/vuex +cd node_modules/vuex +npm install +npm run build +``` diff --git a/docs/ko/intro.md b/docs/ko/intro.md new file mode 100644 index 000000000..3cd9b5cc9 --- /dev/null +++ b/docs/ko/intro.md @@ -0,0 +1,63 @@ +# What is Vuex? + +Vuex is a **state management pattern + library** for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion. It also integrates with Vue's official [devtools extension](https://github.com/vuejs/vue-devtools) to provide advanced features such as zero-config time-travel debugging and state snapshot export / import. + +### What is a "State Management Pattern"? + +Let's start with a simple Vue counter app: + +``` js +new Vue({ + // state + data () { + return { + count: 0 + } + }, + // view + template: ` +

+ `, + // actions + methods: { + increment () { + this.count++ + } + } +}) +``` + +It is a self-contained app with the following parts: + +- The **state**, which is the source of truth that drives our app; +- The **view**, which is just a declarative mapping of the **state**; +- The **actions**, which are the possible ways the state could change in reaction to user inputs from the **view**. + +This is an extremely simple representation of the concept of "one-way data flow": + +

+ +

+ +However, the simplicity quickly breaks down when we have **multiple components that share common state**: + +- Multiple views may depend on the same piece of state. +- Actions from different views may need to mutate the same piece of state. + +For problem one, passing props can be tedious for deeply nested components, and simply doesn't work for sibling components. For problem two, we often find ourselves resorting to solutions such as reaching for direct parent/child instance references or trying to mutate and synchronize multiple copies of the state via events. Both of these patterns are brittle and quickly lead to unmaintainable code. + +So why don't we extract the shared state out of the components, and manage it in a global singleton? With this, our component tree becomes a big "view", and any component can access the state or trigger actions, no matter where they are in the tree! + +In addition, by defining and separating the concepts involved in state management and enforcing certain rules, we also give our code more structure and maintainability. + +This is the basic idea behind Vuex, inspired by [Flux](https://facebook.github.io/flux/docs/overview.html), [Redux](http://redux.js.org/) and [The Elm Architecture](https://guide.elm-lang.org/architecture/). Unlike the other patterns, Vuex is also a library implementation tailored specifically for Vue.js to take advantage of its granular reactivity system for efficient updates. + +![vuex](./images/vuex.png) + +### When Should I Use It? + +Although Vuex helps us deal with shared state management, it also comes with the cost of more concepts and boilerplate. It's a trade-off between short term and long term productivity. + +If you've never built a large-scale SPA and jump right into Vuex, it may feel verbose and daunting. That's perfectly normal - if your app is simple, you will most likely be fine without Vuex. A simple [global event bus](http://vuejs.org/guide/components.html#Non-Parent-Child-Communication) may be all you need. 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 handle state outside of your Vue components, and Vuex will be natural next step for you. There's a good quote from Dan Abramov, the author of Redux: + +> Flux libraries are like glasses: you’ll know when you need them. diff --git a/docs/ko/modules.md b/docs/ko/modules.md new file mode 100644 index 000000000..51ee44bf7 --- /dev/null +++ b/docs/ko/modules.md @@ -0,0 +1,138 @@ +# Modules + +Due to using a single state tree, all state of our application is contained inside one big object. However, as our application grows in scale, the store can get really bloated. + +To help with that, Vuex allows us to divide our store into **modules**. Each module can contain its own state, mutations, actions, getters, and even nested modules - it's fractal all the way down: + +``` js +const moduleA = { + state: { ... }, + mutations: { ... }, + actions: { ... }, + getters: { ... } +} + +const moduleB = { + state: { ... }, + mutations: { ... }, + actions: { ... } +} + +const store = new Vuex.Store({ + modules: { + a: moduleA, + b: moduleB + } +}) + +store.state.a // -> moduleA's state +store.state.b // -> moduleB's state +``` + +### Module Local State + +Inside a module's mutations and getters, The first argument received will be **the module's local state**. + +``` js +const moduleA = { + state: { count: 0 }, + mutations: { + increment: (state) { + // state is the local module state + state.count++ + } + }, + + getters: { + doubleCount (state) { + return state.count * 2 + } + } +} +``` + +Similarly, inside module actions, `context.state` will expose the local state, and root state will be exposed as `context.rootState`: + +``` js +const moduleA = { + // ... + actions: { + incrementIfOdd ({ state, commit }) { + if (state.count % 2 === 1) { + commit('increment') + } + } + } +} +``` + +Also, inside module getters, the root state will be exposed as their 3rd argument: + +``` js +const moduleA = { + // ... + getters: { + sumWithRootCount (state, getters, rootState) { + return state.count + rootState.count + } + } +} +``` + +### Namespacing + +Note that actions, mutations and getters inside modules are still registered under the **global namespace** - this allows multiple modules to react to the same mutation/action type. You can namespace the module assets yourself to avoid name clashing by prefixing or suffixing their names. And you probably should if you are writing a reusable Vuex module that will be used in unknown environments. For example, we want to create a `todos` module: + +``` js +// types.js + +// define names of getters, actions and mutations as constants +// and they are prefixed by the module name `todos` +export const DONE_COUNT = 'todos/DONE_COUNT' +export const FETCH_ALL = 'todos/FETCH_ALL' +export const TOGGLE_DONE = 'todos/TOGGLE_DONE' +``` + +``` js +// modules/todos.js +import * as types from '../types' + +// define getters, actions and mutations using prefixed names +const todosModule = { + state: { todos: [] }, + + getters: { + [types.DONE_COUNT] (state) { + // ... + } + }, + + actions: { + [types.FETCH_ALL] (context, payload) { + // ... + } + }, + + mutations: { + [types.TOGGLE_DONE] (state, payload) { + // ... + } + } +} +``` + +### Dynamic Module Registration + +You can register a module **after** the store has been created with the `store.registerModule` method: + +``` js +store.registerModule('myModule', { + // ... +}) +``` + +The module's state will be exposed as `store.state.myModule`. + +Dynamic module registration makes it possible for other Vue plugins to also leverage Vuex for state management by attaching a module to the application's store. For example, the [`vuex-router-sync`](https://github.com/vuejs/vuex-router-sync) library integrates vue-router with vuex by managing the application's route state in a dynamically attached module. + +You can also remove a dynamically registered module with `store.unregisterModule(moduleName)`. Note you cannot remove static modules (declared at store creation) with this method. diff --git a/docs/ko/mutations.md b/docs/ko/mutations.md new file mode 100644 index 000000000..3b3bc4935 --- /dev/null +++ b/docs/ko/mutations.md @@ -0,0 +1,186 @@ +# Mutations + +The only way to actually change state in a Vuex store is by committing a mutation. Vuex mutations are very similar to events: each mutation has a string **type** and a **handler**. The handler function is where we perform actual state modifications, and it will receive the state as the first argument: + +``` js +const store = new Vuex.Store({ + state: { + count: 1 + }, + mutations: { + increment (state) { + // mutate state + state.count++ + } + } +}) +``` + +You cannot directly call a mutation handler. The options here is more like event registration: "When a mutation with type `increment` is triggered, call this handler." To invoke a mutation handler, you need to call **store.commit** with its type: + +``` js +store.commit('increment') +``` + +### Commit with Payload + +You can pass an additional argument to `store.commit`, which is called the **payload** for the mutation: + +``` js +// ... +mutations: { + increment (state, n) { + state.count += n + } +} +``` +``` js +store.commit('increment', 10) +``` + +In most cases, the payload should be an object so that it can contain multiple fields, and the recorded mutation will also be more descriptive: + +``` js +// ... +mutations: { + increment (state, payload) { + state.count += payload.amount + } +} +``` +``` js +store.commit('increment', { + amount: 10 +}) +``` + +### Object-Style Commit + +An alternative way to commit a mutation is by directly using an object that has a `type` property: + +``` js +store.commit({ + type: 'increment', + amount: 10 +}) +``` + +When using object-style commit, the entire object will be passed as the payload to mutation handlers, so the handler remains the same: + +``` js +mutations: { + increment (state, payload) { + state.count += payload.amount + } +} +``` + +### Silent Commit + +> Note: This is a feature that will likely be deprecated once we implement mutation filtering in the devtools. + +By default, every committed mutation is sent to plugins (e.g. the devtools). However in some scenarios you may not want the plugins to record every state change. Multiple commits to the store in a short period or polled do not always need to be tracked. In such cases you can pass a third argument to `store.commit` to "silence" that specific mutation from plugins: + +``` js +store.commit('increment', { + amount: 1 +}, { silent: true }) + +// with object-style commit +store.commit({ + type: 'increment', + amount: 1 +}, { silent: true }) +``` + +### Mutations Follow Vue's Reactivity Rules + +Since a Vuex store's state is made reactive by Vue, when we mutate the state, Vue components observing the state will update automatically. This also means Vuex mutations are subject to the same reactivity caveats when working with plain Vue: + +1. Prefer initializing your store's initial state with all desired fields upfront. + +2. When adding new properties to an Object, you should either: + + - Use `Vue.set(obj, 'newProp', 123)`, or - + + - Replace that Object with a fresh one. For example, using the stage-3 [object spread syntax](https://github.com/sebmarkbage/ecmascript-rest-spread) we can write it like this: + + ``` js + state.obj = { ...state.obj, newProp: 123 } + ``` + +### Using Constants for Mutation Types + +It is a commonly seen pattern to use constants for mutation types in various Flux implementations. This 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 +// store.js +import Vuex from 'vuex' +import { SOME_MUTATION } from './mutation-types' + +const store = new Vuex.Store({ + state: { ... }, + 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. + +### Mutations Must Be Synchronous + +One important rule to remember is that **mutation handler functions must be synchronous**. Why? Consider the following example: + +``` js +mutations: { + someMutation (state) { + api.callAsyncMethod(() => { + state.count++ + }) + } +} +``` + +Now imagine we are debugging the app and looking at the devtool's mutation logs. For every mutation logged, the devtool will need to capture a "before" and "after" snapshots of the state. However, the asynchronous callback inside the example mutation above makes that impossible: the callback is not called yet when the mutation is committed, and there's no way for the devtool to know when the callback will actually be called - any state mutation performed in the callback is essentially un-trackable! + +### Committing Mutations in Components + +You can commit mutations in components with `this.$store.commit('xxx')`, or use the `mapMutations` helper which maps component methods to `store.commit` calls (requires root `store` injection): + +``` js +import { mapMutations } from 'vuex' + +export default { + // ... + methods: { + ...mapMutations([ + 'increment' // map this.increment() to this.$store.commit('increment') + ]), + ...mapMutations({ + add: 'increment' // map this.add() to this.$store.commit('increment') + }) + } +} +``` + +### On to Actions + +Asynchronicity combined with state mutation can make your program very hard to reason about. For example, when you call two methods both with async callbacks that mutate the state, how do you know when they are called and which callback was called first? This is exactly why we want to separate the two concepts. In Vuex, **mutations are synchronous transactions**: + +``` js +store.commit('increment') +// any state change that the "increment" mutation may cause +// should be done at this moment. +``` + +To handle asynchronous operations, let's introduce [Actions](actions.md). diff --git a/docs/ko/plugins.md b/docs/ko/plugins.md new file mode 100644 index 000000000..3dfa04299 --- /dev/null +++ b/docs/ko/plugins.md @@ -0,0 +1,120 @@ +# Plugins + +Vuex stores accept the `plugins` option that exposes hooks for each mutation. A Vuex plugin is simply a function that receives the store as the only argument: + +``` js +const myPlugin = store => { + // called when the store is initialized + store.subscribe((mutation, state) => { + // called after every mutation. + // The mutation comes in the format of { type, payload }. + }) +} +``` + +And can be used like this: + +``` js +const store = new Vuex.Store({ + // ... + plugins: [myPlugin] +}) +``` + +### Committing Mutations Inside Plugins + +Plugins are not allowed to directly mutate state - similar to your components, they can only trigger changes by committing mutations. + +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 +export default function createWebSocketPlugin (socket) { + return store => { + socket.on('data', data => { + store.commit('receiveData', data) + }) + store.subscribe(mutation => { + if (mutation.type === 'UPDATE_DATA') { + socket.emit('update', mutation.payload) + } + }) + } +} +``` + +``` js +const plugin = createWebSocketPlugin(socket) + +const store = new Vuex.Store({ + state, + mutations, + plugins: [plugin] +}) +``` + +### Taking State Snapshots + +Sometimes a plugin may want to receive "snapshots" of the state, and also compare the post-mutation state with pre-mutation state. To achieve that, you will need to perform a deep-copy on the state object: + +``` js +const myPluginWithSnapshot = store => { + let prevState = _.cloneDeep(store.state) + store.subscribe((mutation, state) => { + let nextState = _.cloneDeep(state) + + // compare prevState and nextState... + + // save state for next mutation + prevState = nextState + }) +} +``` + +**Plugins that take state snapshots should be used only during development.** When using Webpack or Browserify, we can let our build tools handle that for us: + +``` js +const store = new Vuex.Store({ + // ... + plugins: process.env.NODE_ENV !== 'production' + ? [myPluginWithSnapshot] + : [] +}) +``` + +The plugin will be used by default. For production, you will need [DefinePlugin](https://webpack.github.io/docs/list-of-plugins.html#defineplugin) for Webpack or [envify](https://github.com/hughsk/envify) for Browserify to convert the value of `process.env.NODE_ENV !== 'production'` to `false` for the final build. + +### 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: + +``` js +import createLogger from 'vuex/dist/logger' + +const store = new Vuex.Store({ + plugins: [createLogger()] +}) +``` + +The `createLogger` function takes a few options: + +``` js +const logger = createLogger({ + collapsed: false, // auto-expand logged mutations + transformer (state) { + // transform the state before logging it. + // for example return only a specific sub-tree + return state.subTree + }, + mutationTransformer (mutation) { + // mutations are logged in the format of { type, payload } + // we can format it any way we want. + return mutation.type + } +}) +``` + +The logger file can also be included directly via a ` @@ -27,7 +27,7 @@ npm install vuex yarn add vuex ``` -When used with a module system, you must explicitly install Vuex via `Vue.use()`: +모듈 시스템과 함께 사용하면 `Vue.use()`를 통해 Vuex를 명시적으로 추가해야 합니다. ``` js import Vue from 'vue' @@ -36,12 +36,12 @@ import Vuex from 'vuex' Vue.use(Vuex) ``` -You don't need to do this when using global script tags. +전역 스크립트 태그를 사용할 때는 이 작업을 할 필요가 없습니다. -### Dev Build +### 개발용 빌드 + +최신 dev 빌드를 사용하고 싶은 경우 직접 GitHub에서 클론하고 `vuex`를 직접 빌드 해야합니다. -You will have to clone directly from GitHub and build `vuex` yourself if -you want to use the latest dev build. ``` bash git clone https://github.com/vuejs/vuex.git node_modules/vuex From 660fd1739a82466e55578eef883a57948d32c1e1 Mon Sep 17 00:00:00 2001 From: ChangJoo Park Date: Sun, 11 Dec 2016 09:56:45 +0900 Subject: [PATCH 03/20] intro --- docs/ko/intro.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/ko/intro.md b/docs/ko/intro.md index 3cd9b5cc9..dc84c82db 100644 --- a/docs/ko/intro.md +++ b/docs/ko/intro.md @@ -1,24 +1,24 @@ -# What is Vuex? +# Vuex가 무엇인가요? -Vuex is a **state management pattern + library** for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion. It also integrates with Vue's official [devtools extension](https://github.com/vuejs/vue-devtools) to provide advanced features such as zero-config time-travel debugging and state snapshot export / import. +Vuex는 Vue.js 애플리케이션에 대한 **상태 관리 패턴 + 라이브러리** 입니다. 애플리케이션의 모든 컴포넌트에 대한 중앙 집중식 저장소 역할을 하며 예측 가능한 방식으로 상태를 변경할 수 있습니다. 또한 Vue의 공식 [devtools 확장 프로그램](https://github.com/vuejs/vue-devtools)과 통합되어 설정 시간이 필요 없는 디버깅 및 상 태 스냅 샷 내보내기/가져오기와 같은 고급 기능을 제공합니다. -### What is a "State Management Pattern"? +### "상태 관리 패턴"이란 무엇인가요? -Let's start with a simple Vue counter app: +간단한 Vue 카운터 앱부터 시작 해보겠습니다. ``` js new Vue({ - // state + // 상태 data () { return { count: 0 } }, - // view + // 뷰 template: `
{{ count }}
`, - // actions + // 액션 methods: { increment () { this.count++ @@ -27,37 +27,37 @@ new Vue({ }) ``` -It is a self-contained app with the following parts: +다음과 같은 기능을 가진 앱입니다. -- The **state**, which is the source of truth that drives our app; -- The **view**, which is just a declarative mapping of the **state**; -- The **actions**, which are the possible ways the state could change in reaction to user inputs from the **view**. +- **상태** 는 앱을 작동하는 원본 소스 입니다. +- **뷰** 는 **상태의** 선언적 매핑입니다. +- **액션** 은 **뷰** 에서 사용자 입력에 대해 반응적으로 상태를 바꾸는 방법입니다. -This is an extremely simple representation of the concept of "one-way data flow": +이것은 "단방향 데이터 흐름" 개념의 매우 단순한 표현입니다.

-However, the simplicity quickly breaks down when we have **multiple components that share common state**: +그러나 **공통의 상태를 공유하는 여러 컴포넌트** 가 있는 경우 단순함이 빠르게 저하됩니다. -- Multiple views may depend on the same piece of state. -- Actions from different views may need to mutate the same piece of state. +- 여러 뷰는 같은 상태에 의존합니다. +- 서로 다른 뷰의 작업은 동일한 상태를 반영해야 할 수 있습니다. -For problem one, passing props can be tedious for deeply nested components, and simply doesn't work for sibling components. For problem two, we often find ourselves resorting to solutions such as reaching for direct parent/child instance references or trying to mutate and synchronize multiple copies of the state via events. Both of these patterns are brittle and quickly lead to unmaintainable code. +첫번째 문제의 경우, 지나치게 중첩된 컴포넌트는 통과하는 prop는 장황할 수 있으며 형제 컴포넌트에서는 작동하지 않습니다. 두번째 문제의 경우 직접 부모/자식 인스턴스를 참조하거나 이벤트를 통해 상태의 여러 복사본을 변경 및 동기화 하려는 등의 해결 방법을 사용해야 합니다. 이러한 패턴은 모두 부서지기 쉽고 유지보수가 불가능한 코드로 빠르게 변경됩니다. -So why don't we extract the shared state out of the components, and manage it in a global singleton? With this, our component tree becomes a big "view", and any component can access the state or trigger actions, no matter where they are in the tree! +그렇다면 컴포넌트에서 공유된 상태를 추출하고 이를 글로벌 싱글톤에서 관리하지 않는 이유는 무엇입니까? 이를 통해 우리의 컴포넌트 트리는 커다란 "뷰"가 되며 모든 컴포넌트는 트리에 상관없이 상태에 액세스하거나 동작을 트리거 할 수 있습니다! -In addition, by defining and separating the concepts involved in state management and enforcing certain rules, we also give our code more structure and maintainability. +또한 상태 관리 및 특정 규칙 적용과 관련된 개념을 정의하고 분리함으로써 코드의 구조와 유지 관리 기능을 향상시킵니다. -This is the basic idea behind Vuex, inspired by [Flux](https://facebook.github.io/flux/docs/overview.html), [Redux](http://redux.js.org/) and [The Elm Architecture](https://guide.elm-lang.org/architecture/). Unlike the other patterns, Vuex is also a library implementation tailored specifically for Vue.js to take advantage of its granular reactivity system for efficient updates. +이는 [Flux](https://facebook.github.io/flux/docs/overview.html), [Redux](http://redux.js.org/), [The Elm Architecture](https://guide.elm-lang.org/architecture/)에서 영감을 받은 Vuex의 기본 아이디어 입니다. 다른 패턴과 달리 Vuex는 Vue.js가 효율적인 업데이트를 위해 세분화된 반응 시스템을 활용하도록 특별히 고안된 라이브러리입니다. ![vuex](./images/vuex.png) -### When Should I Use It? +### 언제 사용해야 하나요? -Although Vuex helps us deal with shared state management, it also comes with the cost of more concepts and boilerplate. It's a trade-off between short term and long term productivity. +Vuex는 공유된 상태 관리를 처리하는 데 유용하지만, 개념에 대한 이해와 시작하는 비용도 함께 듭니다. 그것은 단기간과 장기간 생산성 간의 기회비용이 있습니다. -If you've never built a large-scale SPA and jump right into Vuex, it may feel verbose and daunting. That's perfectly normal - if your app is simple, you will most likely be fine without Vuex. A simple [global event bus](http://vuejs.org/guide/components.html#Non-Parent-Child-Communication) may be all you need. 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 handle state outside of your Vue components, and Vuex will be natural next step for you. There's a good quote from Dan Abramov, the author of Redux: +대규모 SPA를 구축하지 않고 Vuex로 바로 뛰어 들었다면, 시간이 오래 걸리고 힘든일일 것입니다. 이것은 일반 적인 일입니다. 앱이 단순하다면 Vuex없이는 괜찮을 것입니다. 간단한 [글로벌 이벤트 버스](http://vuejs.org/guide/components.html#Non-Parent-Child-Communication)만 있으면됩니다. 그러나 중대형 규모의 SPA를 구축하는 경우 Vue컴포넌트 외부의 상태를 보다 잘 처리할 수 있는 방법을 생각하게 될 가능성이 있으며 Vuex는 자연스럽게 선택할 수 있는 단계가 될 것입니다. Redux의 저자인 Dan Abramov의 좋은 인용이 있습니다. -> Flux libraries are like glasses: you’ll know when you need them. +> Flux 라이브러리는 안경과 같습니다. 필요할 때 알아볼 수 있습니다. From 8bb994a0b8da5fdd9ae1826b71edf7a066aaa1dd Mon Sep 17 00:00:00 2001 From: ChangJoo Park Date: Sun, 11 Dec 2016 11:58:59 +0900 Subject: [PATCH 04/20] getting started --- docs/ko/getting-started.md | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/docs/ko/getting-started.md b/docs/ko/getting-started.md index 4f937a465..334b54245 100644 --- a/docs/ko/getting-started.md +++ b/docs/ko/getting-started.md @@ -1,19 +1,18 @@ -# Getting Started +# 시작하기 -At the center of every Vuex application is the **store**. A "store" is basically a container that holds your application **state**. There are two things that makes a Vuex store different from a plain global object: +모든 Vuex 애플리케이션의 중심에는 **store** 가 있습니다. "store"는 기본적으로 애플리케이션 **상태** 를 보유하고있는 컨테이너입니다. Vuex 저장소가 일반 전역 개체와 두 가지 다른 점이 있습니다. -1. Vuex stores are reactive. When Vue components retrieve state from it, they will reactively and efficiently update if the store's state changes. +1. Vuex store는 반응형 입니다. Vue 컴포넌트는 상태를 검색할 때 저장소의 상태가 변경되면 효율적으로 대응하고 업데이트합니다. +2. 저장소의 상태를 직접 변경할 수 없습니다. 저장소의 상태를 변경하는 유일한 방법은 명시적인 **커밋을 이용한 Mutation** 입니다. 이렇게하면 모든 상태에 대한 추적이 가능한 기록이 남을 수 있으며 툴를 사용하여 앱을 더 잘 이해할 수 있습니다. -2. You cannot directly mutate the store's state. The only way to change a store's state is by explicitly **committing mutations**. This ensures every state change leaves a track-able record, and enables tooling that helps us better understand our applications. +### 가장 단순한 저장소 -### The Simplest Store +> **참고:** 모든 예제는 ES2015 문법을 사용합니다. 사용하고 있지 않은 경우 [꼭 사용해야 합니다!](https://babeljs.io/docs/learn-es2015/) -> **NOTE:** We will be using ES2015 syntax for code examples for the rest of the docs. If you haven't picked it up, [you should](https://babeljs.io/docs/learn-es2015/)! - -After [installing](installation.md) Vuex, let's create a store. It is pretty straightforward - just provide an initial state object, and some mutations: +Vuex를 [설치](installation.md)한 후 저장소를 만들어 봅시다. 매우 간단합니다. 초기 상태 객체와 일부 mutation을 제공하십시오. ``` js -// Make sure to call Vue.use(Vuex) first if using a module system +// 모듈 시스템을 사용하는 경우 Vue.use(Vuex)를 먼저 호출해야합니다. const store = new Vuex.Store({ state: { @@ -27,7 +26,7 @@ const store = new Vuex.Store({ }) ``` -Now, you can access the state object as `store.state`, and trigger a state change with the `store.commit` method: +이제 state 객체에 `store.state`로 접근하여 `store.commit` 메소드로 상태 변경을 트리거 할 수 있습니다. ``` js store.commit('increment') @@ -35,10 +34,10 @@ store.commit('increment') console.log(store.state.count) // -> 1 ``` -Again, the reason we are committing a mutation instead of changing `store.state.count` directly, is because we want to explicitly track it. This simple convention makes your intention more explicit, so that you can reason about state changes in your app better when reading the code. In addition, this gives us the opportunity to implement tools that can log every mutation, take state snapshots, or even perform time travel debugging. +다시 말해, `store.state.count`를 직접 변경하는 대신 Mutation을 수행하는 이유는 명시적으로 추적을 하기 때문입니다. 이 간단한 규칙에 따라 의도를보다 명확하게 표현할 수 있으므로 코드를 읽을 때 상태 변화를 더 잘 지켜볼 수 있습니다. 또한 모든 Mutation을 기록하고 상태 스냅샷을 저장하거나 시간 흐름에 따라 디버깅을 할 수 있는 도구를 제공합니다. -Using store state in a component simply involves returning the state within a computed property, because the store state is reactive. Triggering changes simply means committing mutations in component methods. +컴포넌트 안에서 저장소 상태를 사용하는 것은 단순히 계산된 속성 내에서 상태를 반환하는 것입니다. 변경을 트리거하는 것은 컴포넌트 메소드에서 변경을 커밋하는 것을 의미합니다. -Here's an example of the [most basic Vuex counter app](https://jsfiddle.net/yyx990803/n9jmu5v7/). +다음은 [가장 기본적인 Vuex 카운터 앱](https://jsfiddle.net/yyx990803/n9jmu5v7/)의 예입니다. -Next, we will discuss each core concept in much finer details, starting with [State](state.md). +이제, 우리는 각 핵심 개념에 대해 더 자세히 설명 할 것입니다. [State](state.md)부터 시작해 보겠습니다. From f647bcfaf6d554a951a97c1587fd0116aaca8bba Mon Sep 17 00:00:00 2001 From: ChangJoo Park Date: Sun, 11 Dec 2016 11:59:04 +0900 Subject: [PATCH 05/20] state --- docs/ko/state.md | 52 ++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/ko/state.md b/docs/ko/state.md index 6fe1a2728..03fc8c9e5 100644 --- a/docs/ko/state.md +++ b/docs/ko/state.md @@ -1,17 +1,17 @@ -# State +# 상태 -### Single State Tree +### 단일 상태 트리 -Vuex uses a **single state tree** - that is, this single object contains all your application level state and serves as the "single source of truth". This also means usually you will have only one store for each application. A single state tree makes it straightforward to locate a specific piece of state, and allows us to easily take snapshots of the current app state for debugging purposes. +Vuex는 **단일 상태 트리** 를 사용합니다. 즉, 이 단일 객체는 모든 응용 프로그램 수준의 상태를 포함하며 "원본 소스" 역할을 합니다. 이는 각 응용 프로그램마다 하나의 저장소만 갖게 된다는 것을 의미합니다. 단일 상태 트리를 사용하면 특정 상태를 쉽게 찾을 수 있으므로 디버깅을 위해 현재 앱 상태의 스냅 샷을 쉽게 가져올 수 있습니다. -The single state tree does not conflict with modularity - in later chapters we will discuss how to split your state and mutations into sub modules. +단일 상태 트리는 모듈성과 충돌하지 않습니다. 나중에 상태와 변이를 하위 모듈로 분할하는 방법에 대해 설명합니다. -### Getting Vuex State into Vue Components +### Vuex 상태를 Vue 컴포넌트에서 가져오기 -So how do we display state inside the store in our Vue components? Since Vuex stores are reactive, the simplest way to "retrieve" state from it is simply returning some store state from within a [computed property](http://vuejs.org/guide/computed.html): +그러면 Vue 컴포넌트에서 저장소 내부의 상태를 어떻게 표시하나요? Vuex 저장소는 반응적이기 때문에 저장소에서 상태를 "검색"하는 가장 간단한 방법은 [계산된 속성](http://vuejs.org/guide/computed.html)내에서 일부 저장소 상태를 가져오는 것입니다. ``` js -// let's create a Counter component +// Counter 컴포넌트를 만듭니다 const Counter = { template: `
{{ count }}
`, computed: { @@ -22,17 +22,17 @@ const Counter = { } ``` -Whenever `store.state.count` changes, it will cause the computed property to re-evaluate, and trigger associated DOM updates. +`store.state.count`가 변경되면 계산된 속성이 다시 변경되고 관련 DOM 업데이트가 트리거됩니다. -However, this pattern causes the component to rely on the global store singleton. When using a module system, it requires importing the store in every component that uses store state, and also requires mocking when testing the component. +그러나 이 패턴은 컴포넌트가 전역 저장소 단독 항목에 의존하게합니다. 모듈 시스템을 사용할 때는 저장소 상태를 사용하는 모든 컴포넌트에서 저장소를 가져와야하며 컴포넌트를 테스트 할 때는 가짜데이터가 필요합니다. -Vuex provides a mechanism to "inject" the store into all child components from the root component with the `store` option (enabled by `Vue.use(Vuex)`): +Vuex는 `store` 옵션(`Vue.use (Vuex)`에 의해 가능)으로 루트 컴포넌트의 모든 자식 컴포넌트에 저장소를 "주입"하는 메커니즘을 제공합니다. ``` js const app = new Vue({ el: '#app', - // provide the store using the "store" option. - // this will inject the store instance to all child components. + // "store" 옵션을 사용하여 저장소를 제공하십시오. + // 그러면 모든 하위 컴포넌트에 저장소 인스턴스가 삽입됩니다. store, components: { Counter }, template: ` @@ -43,7 +43,7 @@ const app = new Vue({ }) ``` -By providing the `store` option to the root instance, the store will be injected into all child components of the root and will be available on them as `this.$store`. Let's update our `Counter` implementation: +루트 인스턴스에 `store` 옵션을 제공함으로써 저장소는 루트의 모든 하위 컴포넌트에 주입되고 `this.$store`로 사용할 수 있습니다. `Counter` 구현을 수정해야 합니다. ``` js const Counter = { @@ -56,24 +56,24 @@ const Counter = { } ``` -### The `mapState` Helper +### `mapState` 헬퍼 -When a component needs to make use of multiple store state properties or getters, declaring all these computed properties can get repetitive and verbose. To deal with this we can make use of the `mapState` helper which generates computed getter functions for us and help us save some keystrokes: +컴포넌트가 여러 저장소 상태 속성이나 getter를 사용해야하는 경우 계산된 속성을 모두 선언하면 반복적이고 장황해집니다. 이를 처리하기 위해 우리는 계산된 getter 함수를 생성하는 `mapState` 헬퍼를 사용하여 키 입력을 줄일 수 있습니다. ``` js -// in standalone builds helpers are exposed as Vuex.mapState +// 독립 실행 형 빌드에서 헬퍼가 Vuex.mapState로 노출됩니다. import { mapState } from 'vuex' export default { // ... computed: mapState({ - // arrow functions can make the code very succinct! + // 화살표 함수는 코드를 매우 간결하게 만들어 줍니다! count: state => state.count, - // passing the string value 'count' is same as `state => state.count` + // 문자열 값 'count'를 전달하는 것은 `state => state.count`와 같습니다. countAlias: 'count', - // to access local state with `this`, a normal function must be used + // `this`를 사용하여 로컬 상태에 액세스하려면 일반적인 함수를 사용해야합니다 countPlusLocalState (state) { return state.count + this.localCount } @@ -81,29 +81,29 @@ export default { } ``` -We can also pass a string array to `mapState` when the name of mapped computed property is same as state sub tree name. +또한 매핑 된 계산된 속성의 이름이 상태 하위 트리 이름과 같을 때 문자열 배열을 `mapState`에 전달할 수 있습니다. ``` js computed: mapState([ - // map this.count to store.state.count + // this.count를 store.state.count에 매핑 합니다. 'count' ]) ``` -### Object Spread Operator +### 객체 전파 연산자 -Note that `mapState` returns an object. How do we use it in combination with other local computed properties? Normally, we'd have to use a utility to merge multiple objects into one so that we can pass the final object to `computed`. However with the [object spread operator](https://github.com/sebmarkbage/ecmascript-rest-spread) (which is a stage-3 ECMAScript proposal), we can greatly simplify the syntax: +`mapState`는 객체를 반환합니다. 다른 로컬 영역의 계산된 속성과 함께 사용하려면 어떻게 해야 하나요? 일반적으로, 최종 객체를 `computed`에 전달할 수 있도록 여러 객체를 하나로 병합하는 유틸리티를 사용해야합니다. 그러나 (3 단계 ECMAScript 스펙) [객체 확산 연산자](https://github.com/sebmarkbage/ecmascript-rest-spread)을 사용하면 문법을 매우 단순화 할 수 있습니다. ``` js computed: { localComputed () { /* ... */ }, - // mix this into the outer object with the object spread operator + // 이것을 객체 전파 연산자를 사용하여 외부 객체에 추가 하십시오. ...mapState({ // ... }) } ``` -### Components Can Still Have Local State +### 컴포넌트에는 여전히 로컬 상태가 있을 수 있습니다. -Using Vuex doesn't mean you should put **all** the state in Vuex. Although putting more state into Vuex makes your state mutations more explicit and debuggable, sometimes it could also make the code more verbose and indirect. If a piece of state strictly belongs to a single component, it could be just fine leaving it as local state. You should weigh the trade-offs and make decisions that fit the development needs of your app. +Vuex를 사용한다고해서 Vuex에 **모든** 상태를 넣어야하는 것은 아닙니다. Vuex에 더 많은 상태를 넣으면 상태 변이가 더 명확하고 디버그 가능하지만, 때로는 코드를 보다 장황하고 간접적으로 만들 수 있습니다. 상태 조각이 단일 컴포넌트에 엄격하게 속한 경우 로컬 상태로 남겨 둘 수 있습니다. 기회비용을 판단하고 앱의 개발 요구에 맞는 결정을 내려야 합니다. From 90ad4a8812b6e597d32996b8dbe3bd3122639dbb Mon Sep 17 00:00:00 2001 From: ChangJoo Park Date: Sun, 11 Dec 2016 12:05:41 +0900 Subject: [PATCH 06/20] getters --- docs/ko/getters.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/ko/getters.md b/docs/ko/getters.md index b4ab7941e..39e5042e7 100644 --- a/docs/ko/getters.md +++ b/docs/ko/getters.md @@ -1,6 +1,6 @@ # Getters -Sometimes we may need to compute derived state based on store state, for example filtering through a list of items and counting them: +때로는 저장소 상태를 기반하는 상태를 계산해야 할 수도 있습니다.(예: 아이템 리스트를 필터링하고 계산) ``` js computed: { @@ -10,9 +10,9 @@ computed: { } ``` -If more than one component needs to make use of this, we have to either duplicate the function, or extract it into a shared helper and import it in multiple places - both are less than ideal. +둘 이상의 컴포넌트가 이를 사용 해야하는 경우 함수를 복제하거나 공유된 헬퍼를 추출하여 여러 위치에서 가져와야합니다. 둘 다 이상적이지 않습니다. -Vuex allows us to define "getters" in the store (think of them as computed properties for stores). Getters will receive the state as their 1st argument: +Vuex를 사용하면 저장소에서 "getters"를 정의 할 수 있습니다(저장소의 계산된 속성으로 생각됩니다). Getters는 첫 번째 전달인자로 상태를 받습니다. ``` js const store = new Vuex.Store({ @@ -30,13 +30,13 @@ const store = new Vuex.Store({ }) ``` -The getters will be exposed on the `store.getters` object: +getters는 `store.getters` 객체에 노출 됩니다. ``` js store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }] ``` -Getters will also receive other getters as the 2nd argument: +Getters는 두 번째 전달인자로 다른 getter도 받게됩니다. ``` js getters: { @@ -51,7 +51,7 @@ getters: { store.getters.doneTodosCount // -> 1 ``` -We can now easily make use of it inside any component: +이제 모든 컴포넌트에서 쉽게 사용할 수 있습니다. ``` js computed: { @@ -61,9 +61,9 @@ computed: { } ``` -### The `mapGetters` Helper +### `mapGetters` 헬퍼 -The `mapGetters` helper simply maps store getters to local computed properties: +`mapGetters` 헬퍼는 저장소 getter를 로컬 계산된 속성에 매핑합니다. ``` js import { mapGetters } from 'vuex' @@ -71,7 +71,7 @@ import { mapGetters } from 'vuex' export default { // ... computed: { - // mix the getters into computed with object spread operator + // getter를 객체 전파 연산자로 계산하여 추가합니다. ...mapGetters([ 'doneTodosCount', 'anotherGetter', @@ -81,11 +81,11 @@ export default { } ``` -If you want to map a getter to a different name, use an object: +getter를 다른 이름으로 매핑하려면 객체를 사용합니다. ``` js ...mapGetters({ - // map this.doneCount to store.getters.doneTodosCount + // this.doneCount를 store.getters.doneTodosCount에 매핑하십시오. doneCount: 'doneTodosCount' }) ``` From 4ab83e2b17fe5dd48a0ef0f8fe895c843dad2d3a Mon Sep 17 00:00:00 2001 From: ChangJoo Park Date: Sun, 11 Dec 2016 12:05:47 +0900 Subject: [PATCH 07/20] Add Korean --- docs/LANGS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/LANGS.md b/docs/LANGS.md index ec8d59bae..2bef4f53b 100644 --- a/docs/LANGS.md +++ b/docs/LANGS.md @@ -3,4 +3,5 @@ * [2.0 - Français](fr/) * [2.0 - Русский](ru/) * [2.0 - 日本語](ja/) +* [2.0 - 한국어(Korean)](ko/) * [1.0 Docs](old/) From d2985d5a131d1e9bd4969ea4a1d71a645414c269 Mon Sep 17 00:00:00 2001 From: ChangJoo Park Date: Sun, 11 Dec 2016 12:34:32 +0900 Subject: [PATCH 08/20] mutation --- docs/ko/mutations.md | 75 ++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/docs/ko/mutations.md b/docs/ko/mutations.md index 3b3bc4935..905266b3c 100644 --- a/docs/ko/mutations.md +++ b/docs/ko/mutations.md @@ -1,6 +1,6 @@ -# Mutations +# 변이 -The only way to actually change state in a Vuex store is by committing a mutation. Vuex mutations are very similar to events: each mutation has a string **type** and a **handler**. The handler function is where we perform actual state modifications, and it will receive the state as the first argument: +Vuex 저장소에서 실제로 상태를 변경하는 유일한 방법은 변이하는 것입니다. Vuex 변이는 이벤트와 매우 유사합니다. 각 변이에는 **타입** 문자열 **핸들러** 가 있습니다. 핸들러 함수는 실제 상태 수정을 하는 곳이며, 첫 번째 전달인자로 상태를받습니다. ``` js const store = new Vuex.Store({ @@ -9,22 +9,22 @@ const store = new Vuex.Store({ }, mutations: { increment (state) { - // mutate state + // 상태 변이 state.count++ } } }) ``` -You cannot directly call a mutation handler. The options here is more like event registration: "When a mutation with type `increment` is triggered, call this handler." To invoke a mutation handler, you need to call **store.commit** with its type: +변이 핸들러를 직접 호출 할 수는 없습니다. 이 옵션은 이벤트 등록과 비슷합니다. "타입이 `increment`인 변이가 발생하면이 핸들러를 호출합니다." 변이 핸들러를 호출하려면 해당 타입과 함께 **store.commit** 을 호출해야합니다. ``` js store.commit('increment') ``` -### Commit with Payload +### 페이로드를 가진 커밋 -You can pass an additional argument to `store.commit`, which is called the **payload** for the mutation: +변이에 대해 **payload** 라고하는 `store.commit`에 추가 전달인자를 사용 할 수 있습니다. ``` js // ... @@ -38,7 +38,7 @@ mutations: { store.commit('increment', 10) ``` -In most cases, the payload should be an object so that it can contain multiple fields, and the recorded mutation will also be more descriptive: +대부분의 경우 페이로드는 여러 필드를 포함할 수 있는 객체여야하며 기록 된 변이는 더 이해하기 쉽습니다. ``` js // ... @@ -54,9 +54,9 @@ store.commit('increment', { }) ``` -### Object-Style Commit +### 객체 스타일 커밋 -An alternative way to commit a mutation is by directly using an object that has a `type` property: +변이를 커밋하는 또 다른 방법은 `type` 속성을 가진 객체를 직접 사용하는 것입니다. ``` js store.commit({ @@ -65,7 +65,7 @@ store.commit({ }) ``` -When using object-style commit, the entire object will be passed as the payload to mutation handlers, so the handler remains the same: +객체 스타일 커밋을 사용할 때 전체 객체는 변이 핸들러에 페이로드로 전달되므로 핸들러는 동일하게 유지됩니다. ``` js mutations: { @@ -75,43 +75,43 @@ mutations: { } ``` -### Silent Commit +### 조용한 커밋 -> Note: This is a feature that will likely be deprecated once we implement mutation filtering in the devtools. +> 참고: 이것은 devtools에서 변이 필터링을 구현하면 더 이상 사용되지 않을 예정입니다. -By default, every committed mutation is sent to plugins (e.g. the devtools). However in some scenarios you may not want the plugins to record every state change. Multiple commits to the store in a short period or polled do not always need to be tracked. In such cases you can pass a third argument to `store.commit` to "silence" that specific mutation from plugins: +기본적으로 커밋 된 모든 변이는 플러그인(예: devtools)에 전송됩니다. 그러나 일부 시나리오에서는 플러그인이 모든 상태 변경을 기록하는 것을 원하지 않을 수도 있습니다. 단기간에 저장소에 대한 여러 커밋나 폴링 된 것이 항상 추적될 필요는 없습니다. 이 경우 세 번째 인수를 `store.commit`에 전달하여 플러그인에서 특정 변이를 "조용하게" 할 수 있습니다. ``` js store.commit('increment', { amount: 1 }, { silent: true }) -// with object-style commit +// 객체 스타일 커밋 store.commit({ type: 'increment', amount: 1 }, { silent: true }) ``` -### Mutations Follow Vue's Reactivity Rules +### Vue의 반응성 규칙을 따르는 변이 -Since a Vuex store's state is made reactive by Vue, when we mutate the state, Vue components observing the state will update automatically. This also means Vuex mutations are subject to the same reactivity caveats when working with plain Vue: +Vuex 저장소의 상태는 Vue에 의해 반응하므로, 상태를 변경하면 상태를 관찰하는 Vue 컴포넌트가 자동으로 업데이트됩니다. 이것은 또한 Vuex 변이가 일반 Vue로 작업 할 때 동일한 반응성에 대한 경고를 받을 수 있음을 의미합니다. -1. Prefer initializing your store's initial state with all desired fields upfront. +1. 원하는 모든 필드에 앞서 저장소를 초기화하는 것이 좋습니다. -2. When adding new properties to an Object, you should either: +2. Object에 새 속성을 추가할 때 다음 중 하나를 수행해야합니다. - - Use `Vue.set(obj, 'newProp', 123)`, or - + - `Vue.set(obj, 'newProp', 123)`을 사용하거나, - - Replace that Object with a fresh one. For example, using the stage-3 [object spread syntax](https://github.com/sebmarkbage/ecmascript-rest-spread) we can write it like this: + - 객체를 새로운 것으로 교체하십시오. 예를 들어, 3 단계 [객체 전파 문법](https://github.com/sebmarkbage/ecmascript-rest-spread)을 사용하면 다음과 같이 작성할 수 있습니다. ``` js state.obj = { ...state.obj, newProp: 123 } ``` -### Using Constants for Mutation Types +### 변이 타입에 상수 사용 -It is a commonly seen pattern to use constants for mutation types in various Flux implementations. This 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: +다양한 Flux 구현에서 변이 유형에 상수를 사용하는 것은 일반인 패턴입니다. 이를 통해 코드는 linter와 같은 툴링을 활용할 수 있으며 모든 상수를 단일 파일에 저장하면 공동 작업자가 전체 애플리케이션에서 어떤 변이가 가능한지 한눈에 파악할 수 있습니다. ``` js // mutation-types.js @@ -126,20 +126,20 @@ import { SOME_MUTATION } from './mutation-types' const store = new Vuex.Store({ state: { ... }, mutations: { - // we can use the ES2015 computed property name feature - // to use a constant as the function name + // ES2015에서 계산 된 프로퍼티 이름 기능을 사용하여 + // 상수를 함수 이름으로 사용할 수 있습니다 [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. +상수를 사용할지 여부는 대부분 환경 설정입니다. 개발자가 많은 대규모 프로젝트에서 유용할 수 있지만, 이는 완전히 선택 사항입니다. -### Mutations Must Be Synchronous +### 변이는 무조건 동기적이어야 합니다. -One important rule to remember is that **mutation handler functions must be synchronous**. Why? Consider the following example: +기억 해야할 한 가지 중요한 규칙은 **변이 핸들러 함수는 동기적** 이어야 한다는 것입니다. 왜 그럴까요? 다음 예제를 확인해보십시오. ``` js mutations: { @@ -151,11 +151,11 @@ mutations: { } ``` -Now imagine we are debugging the app and looking at the devtool's mutation logs. For every mutation logged, the devtool will need to capture a "before" and "after" snapshots of the state. However, the asynchronous callback inside the example mutation above makes that impossible: the callback is not called yet when the mutation is committed, and there's no way for the devtool to know when the callback will actually be called - any state mutation performed in the callback is essentially un-trackable! +이제 우리가 앱을 디버깅하고 devtool의 돌연변이 로그를 보고 있다고 상상해보십시오. 기록 된 모든 변이에 대해 devtool은 상태의 "이전" 및 "이후" 스냅 샷을 캡처 해야 합니다. 그러나 위의 예제 변이 내의 비동기 콜백은 불가능합니다. 변이가 커밋 되었을 때 콜백은 아직 호출되지 않으며, 콜백이 실제로 호출 될 시기를 devtool이 알 수 있는 방법이 없습니다. 콜백에서 수행 된 모든 상태 변이는 본질적으로 추적 할 수 없습니다! -### Committing Mutations in Components +### 컴포넌트 안에서 변이 커밋하기 -You can commit mutations in components with `this.$store.commit('xxx')`, or use the `mapMutations` helper which maps component methods to `store.commit` calls (requires root `store` injection): +`this.$store.commit('xxx')`를 사용하여 컴포넌트에서 변이를 수행하거나 컴포넌트 메소드를 `store.commit` 호출에 매핑하는 `mapMutations` 헬퍼를 사용할 수 있습니다 (루트 `store` 주입 필요) ``` js import { mapMutations } from 'vuex' @@ -164,23 +164,22 @@ export default { // ... methods: { ...mapMutations([ - 'increment' // map this.increment() to this.$store.commit('increment') + 'increment' // this.increment()를 this.$store.commit('increment')에 매핑합니다. ]), ...mapMutations({ - add: 'increment' // map this.add() to this.$store.commit('increment') + add: 'increment' // this.add()를 this.$store.commit('increment')에 매핑합니다. }) } } ``` -### On to Actions +### 액션에서 사용 -Asynchronicity combined with state mutation can make your program very hard to reason about. For example, when you call two methods both with async callbacks that mutate the state, how do you know when they are called and which callback was called first? This is exactly why we want to separate the two concepts. In Vuex, **mutations are synchronous transactions**: +비동기성이 상태의 변이와 결합하면 프로그램을 파악하기가 매우 어려워 질 수 있습니다. 예를 들어 상태를 변경하는 두 가지 비동기 콜백 메소드를 호출할 때 호출되는 시점과 먼저 호출 된 콜백을 어떻게 알 수 있습니까? 이것이 우리가 두 개념을 분리하려는 이유입니다. Vuex에서 **변이는 동기적으로 트랜잭션합니다.** ``` js store.commit('increment') -// any state change that the "increment" mutation may cause -// should be done at this moment. +// "increment" 변이가 일으킬 수 있는 모든 상태 변화는 이 순간에 이루어져야합니다. ``` -To handle asynchronous operations, let's introduce [Actions](actions.md). +비동기 작업을 처리하기 위한 [Actions](actions.md)를 소개합시다. From 8ca9b1c778636e3267707faaf8829d5bf5301f58 Mon Sep 17 00:00:00 2001 From: ChangJoo Park Date: Sun, 11 Dec 2016 12:54:52 +0900 Subject: [PATCH 09/20] actions --- docs/ko/actions.md | 69 +++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/docs/ko/actions.md b/docs/ko/actions.md index f590cd785..d277b78c7 100644 --- a/docs/ko/actions.md +++ b/docs/ko/actions.md @@ -1,11 +1,12 @@ -# Actions +# 액션 Actions are similar to mutations, the difference being that: +액션은 변이와 유사합니다. 몇가지 다른 점은, -- Instead of mutating the state, actions commit mutations. -- Actions can contain arbitrary asynchronous operations. +- 상태를 변이시키는 대신 액션으로 변이에 대한 커밋을 합니다. +- 작업에는 임의의 비동기 작업이 포함될 수 있습니다. -Let's register a simple action: +간단한 액션을 등록합시다. ``` js const store = new Vuex.Store({ @@ -25,9 +26,9 @@ const store = new Vuex.Store({ }) ``` -Action handlers receive a context object which exposes the same set of methods/properties on the store instance, so you can call `context.commit` to commit a mutation, or access the state and getters via `context.state` and `context.getters`. We will see why this context object is not the store instance itself when we introduce [Modules](modules.md) later. +액션 핸들러는 저장소 인스턴스의 같은 메소드들/프로퍼티 세트를 드러내는 컨텍스트 객체를 받습니다. 그래서 `context.commit`을 호출하여 변이를 커밋하거나 `context.state`와 `context.getters`를 통해 상태와 getters에 접근 할 수 있습니다. 나중에 [Modules](modules.md)에서 이 컨텍스트 객체가 저장소 인스턴스 자체가 아닌 이유를 알 수 있습니다. -In practice, we often use ES2015 [argument destructuring](https://github.com/lukehoban/es6features#destructuring) to simplify the code a bit (especially when we need to call `commit` multiple times): +실제로 (특히 `commit`를 여러 번 호출해야하는 경우)코드를 단순화하기 위해 ES2015 [전달인자 분해](https://github.com/lukehoban/es6features#destructuring)를 사용합니다. ``` js actions: { @@ -37,15 +38,15 @@ actions: { } ``` -### Dispatching Actions +### 디스패치 액션 -Actions are triggered with the `store.dispatch` method: +액션은 `store.dispatch` 메소드로 시작됩니다. ``` js store.dispatch('increment') ``` -This may look dumb at first sight: if we want to increment the count, why don't we just call `store.commit('increment')` directly? Well, remember that **mutations must be synchronous**? Actions don't. We can perform **asynchronous** operations inside an action: +처음 볼 때는 이상해 보일 수 있습니다. 카운트를 증가 시키려면 `store.commit('increment')`를 직접 호출하면 어떻습니까? 음, **돌연변이는 동기적** 이어야 한다는 것을 기억하십니까? 액션은 그렇지 않습니다. 액션 내에서 **비동기** 작업을 수행 할 수 있습니다. ``` js actions: { @@ -57,48 +58,49 @@ actions: { } ``` -Actions support the same payload format and object-style dispatch: +액션은 동일한 페이로드 타입과 객체 스타일의 디스패치를 지원합니다. ``` js -// dispatch with a payload +// 페이로드와 함께 디스패치 store.dispatch('incrementAsync', { amount: 10 }) -// dispatch with an object +// 객체와 함께 디스패치 store.dispatch({ type: 'incrementAsync', amount: 10 }) ``` -A more practical example of real-world actions would be an action to checkout a shopping cart, which involves **calling an async API** and **committing multiple mutations**: +액션의 좀 더 실용적인 예는 **비동기 API 호출** 과 **여러 개의 변이를 커밋** 하는 장바구니 결제입니다. ``` js actions: { checkout ({ commit, state }, products) { - // save the items currently in the cart + // 장바구니에 현재있는 항목을 저장하십시오. const savedCartItems = [...state.cart.added] - // send out checkout request, and optimistically - // clear the cart + + // 결제 요청을 보낸 후 장바구니를 비웁니다. commit(types.CHECKOUT_REQUEST) - // the shop API accepts a success callback and a failure callback + + // 상점 API는 성공 콜백 및 실패 콜백을 받습니다. shop.buyProducts( products, - // handle success + // 요청 성공 핸들러 () => commit(types.CHECKOUT_SUCCESS), - // handle failure + // 요청 실패 핸들러 () => commit(types.CHECKOUT_FAILURE, savedCartItems) ) } } ``` -Note we are performing a flow of asynchronous operations, and recording the side effects (state mutations) of the action by committing them. +비동기 작업의 흐름을 수행하고 커밋하여 작업의 사이드이펙트(상태 변이)을 기록합니다. -### Dispatching Actions in Components +### 컴포넌트 내부에서 디스패치 액션 사용하기 -You can dispatch actions in components with `this.$store.dispatch('xxx')`, or use the `mapActions` helper which maps component methods to `store.dispatch` calls (requires root `store` injection): +`this.$store.dispatch('xxx')`를 사용하여 컴포넌트에서 액션을 디스패치하거나 컴포넌트 메소드를 `store.dispatch` 호출에 매핑하는 `mapActions` 헬퍼를 사용할 수 있습니다 (루트 `store` 주입 필요) : ``` js import { mapActions } from 'vuex' @@ -107,20 +109,20 @@ export default { // ... methods: { ...mapActions([ - 'increment' // map this.increment() to this.$store.dispatch('increment') + 'increment' // this.increment()을 this.$store.dispatch('increment')에 매핑 ]), ...mapActions({ - add: 'increment' // map this.add() to this.$store.dispatch('increment') + add: 'increment' // this.add()을 this.$store.dispatch('increment')에 매핑 }) } } ``` -### Composing Actions +### 액션 구성하기 -Actions are often asynchronous, so how do we know when an action is done? And more importantly, how can we compose multiple actions together to handle more complex async flows? +액션은 종종 비동기적 입니다. 그러면 액션이 언제 완료되는지 어떻게 알 수 있습니까? 더 중요한 것은, 복잡한 비동기 흐름을 처리하기 위해 어떻게 여러 작업을 함께 구성 할 수 있습니까? -The first thing to know is that `store.dispatch` can handle Promise returned by the triggered action handler and it also returns Promise: +가장 먼저 알아야 할 점은 `store.dispatch`가 트리거 된 액션 핸들러에 의해 반환된 Promise를 처리 할 수 있으며 Promise를 반환한다는 것입니다. ``` js actions: { @@ -135,7 +137,7 @@ actions: { } ``` -Now you can do: +이렇게 할 수 있습니다. ``` js store.dispatch('actionA').then(() => { @@ -143,7 +145,7 @@ store.dispatch('actionA').then(() => { }) ``` -And also in another action: +그리고 안에 또 다른 액션을 사용할 수 있습니다. ``` js actions: { @@ -156,20 +158,19 @@ actions: { } ``` -Finally, if we make use of [async / await](https://tc39.github.io/ecmascript-asyncawait/), a JavaScript feature landing very soon, we can compose our actions like this: +마지막으로, JavaScript 기능인 [async/await](https://tc39.github.io/ecmascript-asyncawait/)를 사용하면 다음과 같은 작업을 구성 할 수 있습니다. ``` js -// assuming getData() and getOtherData() return Promises - +// getData() 및 getOtherData()가 Promise를 반환한다고 가정합니다. actions: { async actionA ({ commit }) { commit('gotData', await getData()) }, async actionB ({ dispatch, commit }) { - await dispatch('actionA') // wait for actionA to finish + await dispatch('actionA') // actionA가 끝나기를 기다립니다. commit('gotOtherData', await getOtherData()) } } ``` -> It's possible for a `store.dispatch` to trigger multiple action handlers in different modules. In such a case the returned value will be a Promise that resolves when all triggered handlers have been resolved. +> `store.dispatch`가 다른 모듈에서 여러 액션 핸들러를 트리거하는 것이 가능합니다. 이 경우 반환 된 값은 모든 트리거 된 처리기가 완료 되었을 때 처리되는 Promise입니다. From bd5978ad7701135f2089f7ad5ab81a3b76137675 Mon Sep 17 00:00:00 2001 From: ChangJoo Park Date: Sun, 11 Dec 2016 13:09:51 +0900 Subject: [PATCH 10/20] modules --- docs/ko/modules.md | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/ko/modules.md b/docs/ko/modules.md index 51ee44bf7..dd2c217f2 100644 --- a/docs/ko/modules.md +++ b/docs/ko/modules.md @@ -1,8 +1,8 @@ -# Modules +# 모듈 -Due to using a single state tree, all state of our application is contained inside one big object. However, as our application grows in scale, the store can get really bloated. +단일 상태 트리를 사용하기 때문에 응용 프로그램의 모든 상태가 하나의 큰 객체 안에 포함됩니다. 그러나 규모가 커짐에 따라 저장소는 매우 비대해질 수 있습니다. -To help with that, Vuex allows us to divide our store into **modules**. Each module can contain its own state, mutations, actions, getters, and even nested modules - it's fractal all the way down: +이를 위해 Vuex는 저장소를 **모듈** 로 나눌 수 있습니다. 각 모듈은 자체 상태, 변이, 액션, 게터 및 심지어 중첩된 모듈을 포함 할 수 있습니다. ``` js const moduleA = { @@ -25,20 +25,20 @@ const store = new Vuex.Store({ } }) -store.state.a // -> moduleA's state -store.state.b // -> moduleB's state +store.state.a // -> moduleA'의 상태 +store.state.b // -> moduleB'의 상태 ``` -### Module Local State +### 지역 상태 모듈 -Inside a module's mutations and getters, The first argument received will be **the module's local state**. +모듈의 변이와 getter 내부에서 첫 번째 전달인자는 **모듈의 지역 상태** 가됩니다. ``` js const moduleA = { state: { count: 0 }, mutations: { increment: (state) { - // state is the local module state + // state는 지역 모듈 상태 입니다 state.count++ } }, @@ -51,7 +51,7 @@ const moduleA = { } ``` -Similarly, inside module actions, `context.state` will expose the local state, and root state will be exposed as `context.rootState`: +유사하게 모듈 내부에서 `context.state`는 지역 상태를 노출시킬 것이고 루트 상태는 `context.rootState`로 노출 될 것입니다. ``` js const moduleA = { @@ -66,7 +66,7 @@ const moduleA = { } ``` -Also, inside module getters, the root state will be exposed as their 3rd argument: +또한, 모듈 getters 내부, 루트 상태는 그들의 세 번째 전달인자로 노출됩니다. ``` js const moduleA = { @@ -79,15 +79,15 @@ const moduleA = { } ``` -### Namespacing +### 네임스페이스 -Note that actions, mutations and getters inside modules are still registered under the **global namespace** - this allows multiple modules to react to the same mutation/action type. You can namespace the module assets yourself to avoid name clashing by prefixing or suffixing their names. And you probably should if you are writing a reusable Vuex module that will be used in unknown environments. For example, we want to create a `todos` module: +모듈 내의 액션, 변이 및 getter는 여전히 **전역 네임 스페이스** 아래에 등록됩니다. 여러 모듈이 동일한 변이/액션 유형에 반응 할 수 있습니다. 이름 앞에 접두사 또는 접미사를 붙이면 이름 충돌을 피하기 위해 모듈 자신의 네임스페이스를 직접 지정할 수 있습니다. 그리고 알 수 없는 환경에서 사용될 재사용 가능한 Vuex 모듈을 작성하는 경우라면 반드시 사용해야 합니다. 예를 들어,`todos` 모듈을 만들고 싶은 경우 ``` js // types.js -// define names of getters, actions and mutations as constants -// and they are prefixed by the module name `todos` +// getter, 액션, 변이의 이름을 상수로 정의하고 +// 모듈 이름 `todos` 접두어를 붙입니다 export const DONE_COUNT = 'todos/DONE_COUNT' export const FETCH_ALL = 'todos/FETCH_ALL' export const TOGGLE_DONE = 'todos/TOGGLE_DONE' @@ -97,7 +97,7 @@ export const TOGGLE_DONE = 'todos/TOGGLE_DONE' // modules/todos.js import * as types from '../types' -// define getters, actions and mutations using prefixed names +// 접두어로 된 이름을 사용하여 getter, 액션 및 변이 정의 const todosModule = { state: { todos: [] }, @@ -121,9 +121,9 @@ const todosModule = { } ``` -### Dynamic Module Registration +### 동적 모듈 등록 -You can register a module **after** the store has been created with the `store.registerModule` method: +`store.registerModule` 메소드로 저장소가 생성 된 **후에** 모듈을 등록 할 수 있습니다. ``` js store.registerModule('myModule', { @@ -131,8 +131,8 @@ store.registerModule('myModule', { }) ``` -The module's state will be exposed as `store.state.myModule`. +모듈의 상태는`store.state.myModule`으로 노출 됩니다. -Dynamic module registration makes it possible for other Vue plugins to also leverage Vuex for state management by attaching a module to the application's store. For example, the [`vuex-router-sync`](https://github.com/vuejs/vuex-router-sync) library integrates vue-router with vuex by managing the application's route state in a dynamically attached module. +동적 모듈 등록을 사용하면 다른 Vue 플러그인도 응용 프로그램의 저장소에 모듈을 연결하여 상태 관리에 Vuex를 활용할 수 있습니다. 예를 들어 [`vuex-router-sync`](https://github.com/vuejs/vuex-router-sync) 라이브러리는 동적으로 연결된 모듈에서 응용 프로그램의 라우트 상태를 관리하여 vue-router와 vuex를 통합합니다. -You can also remove a dynamically registered module with `store.unregisterModule(moduleName)`. Note you cannot remove static modules (declared at store creation) with this method. +`store.unregisterModule(moduleName)`을 사용하여 동적으로 등록 된 모듈을 제거할 수도 있습니다. 이 방법으로는 정적 모듈(저장소 생성시 선언 됨)을 제거 할 수 없습니다. From f7026218ab406bb9ba109d74021e93339d575277 Mon Sep 17 00:00:00 2001 From: ChangJoo Park Date: Sun, 11 Dec 2016 13:14:48 +0900 Subject: [PATCH 11/20] structure --- docs/ko/structure.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/ko/structure.md b/docs/ko/structure.md index 2ba11e37b..3be902dd3 100644 --- a/docs/ko/structure.md +++ b/docs/ko/structure.md @@ -1,32 +1,34 @@ -# Application Structure +# 애플리케이션 구조 Vuex doesn't really restrict how you structure your code. Rather, it enforces a set of high-level principles: +실제로 Vuex는 코드 구조를 제한하지는 않습니다. 이보다 아래의 고수준 원칙을 강요합니다. -1. Application-level state is centralized in the store. +1. 애플리케이션 레벨의 상태는 중앙 집중된 저장소 입니다. -2. The only way to mutate the state is by committing **mutations**, which are synchronous transactions. +2. 상태를 변경시키는 유일한 방법은 동기 트랜잭션인 **변이** 를 커밋하는 것입니다. -3. Asynchronous logic should be encapsulated in, and can be composed with **actions**. +3. 비동기식 로직은 캡슐화되어야하며 **액션** 으로 구성 됩니다. -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. -For any non-trivial app, we will likely need to leverage modules. Here's an example project structure: +이 규칙을 따른다면 프로젝트를 구조화하는 것은 사용자에게 달려 있습니다. 저장소 파일이 너무 커지면 액션, 돌연변이 및 getter를 개별 파일로 분할하기만 하면됩니다. + +중요한 앱의 경우 모듈을 활용해야 할 가능성이 높습니다. 다음은 프로젝트 구조의 예입니다. ``` bash ├── index.html ├── main.js ├── api -│   └── ... # abstractions for making API requests +│   └── ... # API 요청을 위한 추상화를 포함합니다. ├── components │   ├── App.vue │   └── ... └── store - ├── index.js # where we assemble modules and export the store - ├── actions.js # root actions - ├── mutations.js # root mutations + ├── index.js # 모듈을 조합하고 저장소를 내보내는 곳 입니다. + ├── actions.js # 루트 액션 + ├── mutations.js # 루트 변이 └── modules -    ├── cart.js # cart module -    └── products.js # products module +    ├── cart.js # cart 모듈 +    └── products.js # products 모듈 ``` -As a reference, check out the [Shopping Cart Example](https://github.com/vuejs/vuex/tree/dev/examples/shopping-cart). +참고 사항으로, [장바구니 예](https://github.com/vuejs/vuex/tree/dev/examples/shopping-cart)를 확인하십시오. From 5acd8d8d75450b895b88a3ba6e3e584a3639be68 Mon Sep 17 00:00:00 2001 From: ChangJoo Park Date: Sun, 11 Dec 2016 13:18:00 +0900 Subject: [PATCH 12/20] strict --- docs/ko/strict.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/ko/strict.md b/docs/ko/strict.md index 7469f3dbc..985dfc42e 100644 --- a/docs/ko/strict.md +++ b/docs/ko/strict.md @@ -1,6 +1,6 @@ -# Strict Mode +# Strict 모드 -To enable strict mode, simply pass in `strict: true` when creating a Vuex store: +strict 모드를 사용하기 위해, `strict: true`를 Vuex 저장소를 만들 때 추가하면 됩니다. ``` js const store = new Vuex.Store({ @@ -9,13 +9,13 @@ const store = new Vuex.Store({ }) ``` -In strict mode, whenever Vuex state is mutated outside of mutation handlers, an error will be thrown. This ensures that all state mutations can be explicitly tracked by debugging tools. +엄격 모드에서는 Vuex 상태가 변이 핸들러 외부에서 변이 될 때 마다 오류가 발생합니다. 이렇게하면 디버깅 도구로 모든 상태 변이를 명시적으로 추적 할 수 있습니다. -### Development vs. Production +### 개발 vs. 배포 -**Do not enable strict mode when deploying for production!** Strict mode runs a deep watch on the state tree for detecting inappropriate mutations - make sure to turn it off in production to avoid the performance cost. +**배포시 strict 모드를 켜지 마십시오!** Strict 모드는 부적절한 변이를 감지하기 위해 상태 트리를 자세히 관찰합니다. 성능 이슈를 피하기 위해 배포 환경에서 이를 해제 하십시오. -Similar to plugins, we can let the build tools handle that: +플러그인과 마찬가지로 빌드 도구가 다음을 처리하도록 할 수 있습니다. ``` js const store = new Vuex.Store({ From 5b53115250afc4b1e5203050ed56f49294b717af Mon Sep 17 00:00:00 2001 From: ChangJoo Park Date: Sun, 11 Dec 2016 13:21:13 +0900 Subject: [PATCH 13/20] forms --- docs/ko/forms.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/ko/forms.md b/docs/ko/forms.md index 219c6377d..e0d376b36 100644 --- a/docs/ko/forms.md +++ b/docs/ko/forms.md @@ -1,14 +1,14 @@ -# Form Handling +# 폼 핸들링 -When using Vuex in strict mode, it could be a bit tricky to use `v-model` on a piece of state that belongs to Vuex: +strict 모드로 Vuex를 사용하는 경우 Vuex에 포함된 부분에 `v-model`을 사용하는 것은 약간 까다로울 수 있습니다. ``` html ``` -Assuming `obj` is a computed property that returns an Object from the store, the `v-model` here will attempt to directly mutate `obj.message` when the user types in the input. In strict mode, this will result in an error because the mutation is not performed inside an explicit Vuex mutation handler. +`obj`가 저장소에서 객체를 반환하는 계산된 속성이라면, 여기에있는 `v-model`은 사용자가 입력 할 때 `obj.message`를 직접 변경하려고 합니다. strict 모드에서는 Vuex 변이 처리기 내부에서 변이가 수행되지 않으므로 오류가 발생합니다. -The "Vuex way" to deal with it is binding the ``'s value and call an action on the `input` or `change` event: +그것을 다루는 "Vuex 방식"은 ``의 값을 바인딩하고 `input` 또는 `change` 이벤트에 대한 액션을 호출하는 것 입니다. ``` html @@ -27,7 +27,7 @@ methods: { } ``` -And here's the mutation handler: +변이에 대한 핸들러 입니다. ``` js // ... @@ -38,9 +38,9 @@ mutations: { } ``` -### Two-way Computed Property +### 양방향 계산된 속성 -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: +틀림없이, 위의 내용은 `v-model` + 지역 상태보다 좀더 장황 해졌고, `v-model`의 유용한 기능 중 일부를 잃어 버렸습니다. 다른 방법은 setter를 사용하여 양방향 계산된 속성을 사용하는 것입니다. ``` js // ... @@ -55,4 +55,3 @@ computed: { } } ``` - From 57656407c75adc8b91931878407e043be789d7a0 Mon Sep 17 00:00:00 2001 From: ChangJoo Park Date: Sun, 11 Dec 2016 13:23:48 +0900 Subject: [PATCH 14/20] hot-reload --- docs/ko/hot-reload.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/ko/hot-reload.md b/docs/ko/hot-reload.md index 8a3e72f27..8865eabb6 100644 --- a/docs/ko/hot-reload.md +++ b/docs/ko/hot-reload.md @@ -1,8 +1,8 @@ -# Hot Reloading +# 핫 리로딩 Vuex supports hot-reloading mutations, modules, actions and getters during development, using Webpack's [Hot Module Replacement API](https://webpack.github.io/docs/hot-module-replacement.html). You can also use it in Browserify with the [browserify-hmr](https://github.com/AgentME/browserify-hmr/) plugin. -For mutations and modules, you need to use the `store.hotUpdate()` API method: +변이와 모듈의 경우, `store.hotUpdate()` API 메소드를 사용할 필요가 있습니다. ``` js // store.js @@ -24,13 +24,13 @@ const store = new Vuex.Store({ }) if (module.hot) { - // accept actions and mutations as hot modules + // 액션과 변이를 핫 모듈로 받아 들인다. module.hot.accept(['./mutations', './modules/a'], () => { - // require the updated modules - // have to add .default here due to babel 6 module output + // 업데이트 된 모듈은 babel 6 모듈 출력으로 인해 + // .default를 여기에 추가해야합니다. const newMutations = require('./mutations').default const newModuleA = require('./modules/a').default - // swap in the new actions and mutations + // 새로운 액션과 변이로 바꿉니다. store.hotUpdate({ mutations: newMutations, modules: { @@ -41,4 +41,4 @@ if (module.hot) { } ``` -Checkout the [counter-hot example](https://github.com/vuejs/vuex/tree/dev/examples/counter-hot) to play with hot-reload. +[counter-hot 예제](https://github.com/vuejs/vuex/tree/dev/examples/counter-hot)로 핫 리로드를 확인하십시오. From c6c833c03c8ffe9b0ed027e87d052cf24d50a151 Mon Sep 17 00:00:00 2001 From: ChangJoo Park Date: Sun, 11 Dec 2016 14:12:32 +0900 Subject: [PATCH 15/20] plugins --- docs/ko/plugins.md | 53 +++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/docs/ko/plugins.md b/docs/ko/plugins.md index 3dfa04299..7ca573d20 100644 --- a/docs/ko/plugins.md +++ b/docs/ko/plugins.md @@ -1,18 +1,18 @@ -# Plugins +# 플러그인 -Vuex stores accept the `plugins` option that exposes hooks for each mutation. A Vuex plugin is simply a function that receives the store as the only argument: +Vuex 저장소는 각 변이에 대한 훅을 노출하는 `plugins` 옵션을 허용합니다. Vuex 플러그인은 저장소를 유일한 전달인자로 받는 함수입니다. ``` js const myPlugin = store => { - // called when the store is initialized + // 저장소가 초기화 될 때 불립니다. store.subscribe((mutation, state) => { - // called after every mutation. - // The mutation comes in the format of { type, payload }. + // 매 변이시마다 불립니다. + // 변이는 { type, payload } 포맷으로 제공됩니다. }) } ``` -And can be used like this: +그리고 다음과 같이 사용할 수 있습니다. ``` js const store = new Vuex.Store({ @@ -21,11 +21,11 @@ const store = new Vuex.Store({ }) ``` -### Committing Mutations Inside Plugins +### 플러그인 내부에서 변이 커밋하기 -Plugins are not allowed to directly mutate state - similar to your components, they can only trigger changes by committing mutations. +플러그인은 상태를 직접 변이할 수 없습니다. 컴포넌트와 마찬가지로 변이를 커밋하여 변경을 트리거 할 수 있습니다. -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): +변이을 커밋함으로써 플러그인을 사용하여 데이터 소스를 저장소에 동기화 할 수 있습니다. 예를 들어, websocket 데이터 소스를 저장소에 동기화하려면 (이는 사실 인위적인 예제입니다. 실제로`createPlugin` 함수는 더 복잡한 작업을 위해 몇 가지 추가 옵션을 필요로 할 수 있습니다) ``` js export default function createWebSocketPlugin (socket) { @@ -52,9 +52,9 @@ const store = new Vuex.Store({ }) ``` -### Taking State Snapshots +### 상태 스냅샷 가져오기 -Sometimes a plugin may want to receive "snapshots" of the state, and also compare the post-mutation state with pre-mutation state. To achieve that, you will need to perform a deep-copy on the state object: +때로는 플러그인이 상태의 "스냅샷"을 얻고자 할 수 있으며, 또한 변이 이후 상태와 변이 이전 상태를 비교할 수 있습니다. 이를 달성하기 위해서는 상태 객체에 대한 깊은 복사를 수행해야합니다 : ``` js const myPluginWithSnapshot = store => { @@ -62,15 +62,15 @@ const myPluginWithSnapshot = store => { store.subscribe((mutation, state) => { let nextState = _.cloneDeep(state) - // compare prevState and nextState... + // prevState와 nextState를 비교하십시오. - // save state for next mutation + // 다음 변이를 위한 상태 저장 prevState = nextState }) } ``` -**Plugins that take state snapshots should be used only during development.** When using Webpack or Browserify, we can let our build tools handle that for us: +**상태 스냅 샷을 사용하는 플러그인은 개발 중에 만 사용해야합니다.** Webpack 또는 Browserify를 사용하는 경우 빌드 도구가 이를 처리 할 수 있습니다. ``` js const store = new Vuex.Store({ @@ -81,13 +81,14 @@ const store = new Vuex.Store({ }) ``` -The plugin will be used by default. For production, you will need [DefinePlugin](https://webpack.github.io/docs/list-of-plugins.html#defineplugin) for Webpack or [envify](https://github.com/hughsk/envify) for Browserify to convert the value of `process.env.NODE_ENV !== 'production'` to `false` for the final build. +플러그인은 기본적으로 사용됩니다. 배포를 위해서는 Webpack의 [DefinePlugin](https://webpack.github.io/docs/list-of-plugins.html#defineplugin) 또는 [envify](https://github.com/hughsk/envify)가 필요합니다. Browserify가 `process.env.NODE_ENV !== 'production'`의 값을 최종 빌드를 위해 `false`로 변환합니다. -### 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: +> [vue-devtools](https://github.com/vuejs/vue-devtools)를 사용하고 있으면 필요 없을 수 있습니다. + +Vuex에는 일반적인 디버깅을 위한 로거 플러그인이 함께 제공됩니다. ``` js import createLogger from 'vuex/dist/logger' @@ -97,24 +98,24 @@ const store = new Vuex.Store({ }) ``` -The `createLogger` function takes a few options: +`createLogger` 함수는 몇 가지 옵션을 가질 수 있습니다. ``` js const logger = createLogger({ - collapsed: false, // auto-expand logged mutations + collapsed: false, // 로그를 가지는 변이 자동 확장 transformer (state) { - // transform the state before logging it. - // for example return only a specific sub-tree + // 로깅하기전 상태를 변이 하십시오. + // 예를 들어 특정 하위 트리만 반환합니다. return state.subTree }, mutationTransformer (mutation) { - // mutations are logged in the format of { type, payload } - // we can format it any way we want. + // 변이는 { type, payload }의 포맷으로 기록됩니다. + // 원하는 포맷으로 변경할 수 있습니다. return mutation.type } }) ``` -The logger file can also be included directly via a `