yejineee
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
--- tags: vuex --- # Vuex 코어 개념 : state, getters ![](https://i.imgur.com/tX3Orfe.png) vuex는 vue.js의 상태관리 라이브러리이다. 여러 컴포넌트에서 공통된 state를 공유하고자할 때, 발생할 수 있는 문제점들이 있다. 첫 번째는 props를 깊은 컴포넌트에게로 전달해야 하는 문제이다. 두 번째는 직접 부모/자식 인스턴스를 참조하거나, 이벤트를 통해 상태의 여러 복사본을 바꾸거나, 동기화시켜야 하는 등의 해결 방법을 써야 한다. 상태 관리와 뷰를 독립적으로 관리하여, 코드르 좀 더 유지하기 쉽고, 구조적으로 만들 수 있다. Vuex의 기본 아이디어는 Flux, Redux, The Elm Architecture에 있다. ![](https://i.imgur.com/6mFHEjX.png) 작은 SPA를 만든다면, vuex의 store pattern을 사용해도 좋다. SPA의 사이즈가 커진다면, vuex를 사용하여 상태관리를 하는 것이 더 낫다. ### vuex store를 Root Component에 등록하기 ```javascript import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } } }) ``` 위에 있는 가장 간단한 스토어를 만들었으면, `store.state`로 이 스토어의 state에 접근할 수 있다. vue component에서 `this.$store`로 스토어에 접근하게 하려면, **Vue Instance에 생성된 스토어를 추가**해야 한다. Vuex에는 스토어를 Root Component의 `store` 옵션에 둠으로써, 스토어를 모든 child component에 **inject**할 수 있다. `new Vue`로 생성한 root component의 `store` 프로퍼티에 스토어를 추가하자. ```javascript new Vue({ el: '#app', store }) ``` # Core Concepts ## State vuex는 **single state tree**를 사용한다. 이는 "single source of truth"에 따라 하나의 오브젝트에 모든 상태를 저장하고, 제공해주는 것을 의미한다. single state tree도 modularity를 제공한다. state를 나눌 수도 있고, mutation을 하위 모듈로 나눌 수 있다. - vuex의 data는 plain object여야 한다. - inject the store into all child components vuex는 스토어를 루트 컴포넌트에 `store` 옵션으로 넣을 수 있게 하였다. 루트에 스토어를 주입함으로써 하위 컴포넌트에도 스토어가 주입되어 `this.$store`로 스토어에 접근할 수 있게 된다. - inject하지 않고 모듈 시스템을 사용하여 import해오는 것의 문제는? 1. 해당 스토어의 상태를 쓰는 모든 컴포넌트에서 스토어를 import해와야 한다. 2. 컴포넌트 테스트할 때, mocking해야 한다. mobx에서도 스토어를 사용하려면 컴포넌트에서 스토어를 import하거나 inject하거나 둘 중 하나였다. 사실 inject하려면 결국 또 import해오는 것이어서, 둘의 차이를 알 수 없었다. vuex에서는 root에서만 등록하고, subcomponent에서는 아예 import해오는 일이 없으면 inject가 더 편할 것 같긴하다. 컴포넌트 테스트는 개인 플젝할 때는 전혀 고려하지 않은 사항인데, 현업에서는 컴포넌트 또한 테스트를 하는 것 같아서 고려할 대상이 되는 것 같다. - **`mapState`** helper 컴포넌트 내에서 프로퍼티를 사용하려면, `this.$store.state.count`로 접근해야 하는데, 이게 귀찮으니 computed를 만들어서 state를 가져오게 된다. ```javascript // let's create a Counter component const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return store.state.count } } } ``` 그러나, 이 computed를 만드는 작업도 귀찮다. `mapState` helper가 있으면, 자동으로 computed getter 함수를 만들 수 있다. ```javascript // in full builds helpers are exposed as 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` countAlias: 'count', // to access local state with `this`, a normal function must be used countPlusLocalState (state) { return state.count + this.localCount } }) } ``` mapped computed property의 이름이 state sub tree name과 같을 떄, <u>스트링 배열을 mapState에 넘길 수 있다.</u> `count: state => state.count,`이걸 한 번에 해주는 것이다. ```javascript computed: mapState([ // map this.count to store.state.count 'count' ]) ``` - mapState와 기존 computed를 합치려면 ? `object spread operator` ```javascript computed: { localComputed () { /* ... */ }, // mix this into the outer object with the object spread operator ...mapState({ // ... }) } ``` ## Getters store에서의 getter는 store의 computed라고 생각하면 된다. 같은 computed를 중복해서 여러 컴포넌트에서 정의할거라면, store에 getter를 정의하는 것으로 하면 된다. component의 computed와 마찬가지로 store의 getter 또한 **getter가 의존하고 있는 것에 따라 캐싱된**다. 즉, 의존하고 있는 상태값이 변경될 때에만 다시 계산된다. getter의 첫 번째 인자는 state이다. ```javascript 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) } } }) ``` - 프로퍼티처럼 getter에 접근하기 getters는 `store.getters` 객체로 보여진다. 만약 어떠한 getter에서 다른 getter에 접근하고자 하면, 두 번째 인자로 `getters`를 넘겨서 접근하면 된다. ```javascript getters: { // ... doneTodosCount: (state, getters) => { return getters.doneTodos.length } } ``` 컴포넌트에서는 이 getter를 바로 가져다가 사용하면 된다. ```javascript computed: { doneTodosCount () { return this.$store.getters.doneTodosCount } } ``` - 메소드처럼 getter에 접근하기 getter가 함수를 반환하게 하면, 이 함수에 인자를 넣어서 query할 수 있다. closure를 활용한 것! ```javascript getters: { // ... getTodoById: (state) => (id) => { return state.todos.find(todo => todo.id === id) } } ``` ```javascript store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false } ``` - `mapGetters` Helper Store에 있는 getter를 사용하기 위해 컴포넌트에서는 매 번 computed로 바꿔주었다. ```javascript computed: { doneTodosCount () { return this.$store.getters.doneTodosCount } } ``` 이 작업을 자동으로 해주는게 `mapGetters`이다. 이것은 store의 getter를 가져와서 local computed 프로퍼티로 만들어준다. ```javascript import { mapGetters } from 'vuex' export default { // ... computed: { // mix the getters into computed with object spread operator ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) } } ``` 만약 getter의 이름을 바꾸고 싶다면, 객체를 사용하면 된다. ```javascript ...mapGetters({ // map `this.doneCount` to `this.$store.getters.doneTodosCount` doneCount: 'doneTodosCount' }) ``` - 직접 해본 count 예제 스토어! ```javascript import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); const store = new Vuex.Store({ state: { count: 100 }, mutations: { increment(state) { state.count += 1; } }, getters: { minusCount(state) { return state.count * -1; }, minusDoubleCount(state, getters) { return getters.minusCount * 2; }, plusCount: state => num => state.count + num } }); export default store; ``` 컴포넌트! ```javascript import { mapState, mapGetters } from 'vuex'; export default { data() { return { title: "Lillie's Trello", count: 'this is local count' }; }, computed: { // ...mapState(['count']), // 원래는 유효하지만, 이 예제에서는 local state의 count와 이름이 겹쳐서 안됨. ...mapState({ // count: state => state.count, // 원래는 유효하지만, 이 예제에서는 local state의 count와 이름이 겹쳐서 안됨. countAlias: 'count', // string으로 넘기면, state => state.count와 같다. sayLocalCount(state) { // hi this is local count, this is count from store : 100 return `hi ${this.count}, this is count from store : ${state.count}`; } }), myCount() { return this.$store.getters.plusCount(10); }, ...mapGetters(['minusCount']), ...mapGetters({ mdCount: 'minusDoubleCount' }) } }; ```

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully