vuex 시리즈 - Vuex의 디자인 사상을 간단히 분석하다

앞말
이야기를 나누기 전에 모든 앞부분 개념은 종이호랑이라는 말을 항상 기억해야 한다.
Vue든 React이든 모두 상태 관리(state)가 필요합니다. 예를 들어 구성 요소 간에 공유 상태가 필요합니다.공유 상태란?예를 들어 하나의 구성 요소가 다른 구성 요소의 상태를 사용해야 하거나, 하나의 구성 요소가 다른 구성 요소의 상태를 바꾸어야 하는 것은 모두 공유 상태이다.
상태를 효과적으로 관리하지 않으면 상태가 언제, 어떤 원인, 어떻게 변화하는지 통제되지 않아 추적과 테스트가 어렵다.이런 곤란을 겪어보지 않았다면 혼란스러웠을 거라고 간단하게 이해할 수 있다.
소프트웨어 개발에서 일부 통용되는 사상, 예를 들어 격리 변화, 약속이 설정보다 낫다는 등이다. 격리 변화는 추상적인 것을 잘 하고 변화하기 쉬운 부분을 공통성을 찾아 격리하고 다른 코드에 영향을 주지 말라는 것이다.약속이 설정보다 낫다는 것은 많은 것들이다. 우리는 반드시 많은 설정을 쓰지 않아도 된다. 예를 들어 우리 몇 사람이 약속하면view 폴더에 보기만 넣을 수 있고 필터를 넣을 수 없다. 필터는 반드시 Filter 폴더에 넣어야 한다. 이것은 약속이다. 약속한 후에 우리는 많은 설정 파일을 쓰지 않아도 된다. 우리는 모든 보기를 찾아야 한다.뷰 폴더에서 직접 찾으면 돼요.
이러한 사상에 따라 상태 관리에 대한 해결 방향은 구성 요소 간에 공유해야 하는 상태를 추출하고 특정한 약정에 따라 통일적으로 관리하여 상태의 변화를 예측할 수 있도록 하는 것이다.
 
vuex
공식 설명: Vuex는 전문적으로 Vue를 위한 것이다.js 응용 프로그램 개발의 상태 관리 모드입니다.중앙 집중식 스토리지 관리 애플리케이션의 모든 구성 요소의 상태를 적용하고 적절한 규칙으로 상태를 예측 가능한 방식으로 변경합니다.
대사: 데이터(data)에 대한 통일된 관리, 데이터 처리가 관련되면 vuex에 들어가세요!마치 슈퍼마켓이 상품에 대한 통일된 관리와 같다.
디자인 사상: Vuex는 전체적으로 하나의 대상을 유지하고 단일 디자인 모델을 사용했다.이 전역 대상에서 모든 속성은 응답식이며, 임의의 속성이 바뀌면 이 속성에 사용된 구성 요소가 업데이트됩니다.또한 commit의 방식으로만 상태를 바꿀 수 있고 단방향 데이터 흐름 모델을 실현했다.
 
3. 원본 코드 해석
store 대상에 state라는 속성이 있습니다.state는 모든 응용 단계의 상태를 포함합니다.응용 프로그램의 구성 요소들이state를 사용하면 최신 상태와 동기화됩니다.state는 vue의 데이터와 같지만 전체 응용 프로그램의 데이터입니다.사실 vuex가 vue의 양방향 데이터 연결을 실현하는 것과 같은지 생각해서object를 만들었어요.defineproperty () 의 처리입니다.
우리는 store 대상이 실례화된 코드에서 시작한다.
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    count: 0
  }
});

new Vue({
  el: '#app',
  store,
  // ...
});
store 객체는 new Vuex를 통과합니다.Store가 실례화되었습니다. src/index.js 파일을 열면 맨 아래 코드에서 vuex가 노출한 Store라는 API를 볼 수 있습니다.
export default {
  Store,
  install,
  mapState,
  mapMutations,
  mapGetters,
  mapActions
}
 
3.1 store
스토어와 같은 아주 긴 코드를 찾았다.낡은 방법은 모든 방법을 접어서 보지 않고 구조 함수constructor만 본다.state와 무관한 코드를 필터링하여 다음과 같이 코드를 단순화할 수 있습니다.
constructor (options = {}) {
  const {
    state = {}
  } = options

  // init root module.
  // this also recursively registers all sub-modules
  // and collects all module getters inside this._wrappedGetters
  installModule(this, state, [], options)

  // initialize the store vm, which is responsible for the reactivity
  // (also registers _wrappedGetters as computed properties)
  resetStoreVM(this, state)
}
순간 코드가 많이 줄어들었기 때문에 다음은installModule와resetStoreVM 두 가지 방법의 실현에 주목하면 된다.이어 좋은 소식이 하나 더 전해지자 설치모듈은 모듈의 초기화에 대해 봤다. 나중에 모듈을 연구해도 늦지 않기 때문에 리셋 스토어 VM만 연구하면 된다.
 
3.2 resetStoreVM
포지셔닝 resetStoreVM 방법, 다시 여과, 그중 Vue.config.silent는 vue 홈페이지에 검색해 봤는데 vue의 모든 로그와 경고를 취소하는 기능이어서 필터를 했습니다. 나머지 코드는 다음과 같습니다.
function resetStoreVM (store, state) {
  // use a Vue instance to store the state tree
  store._vm = new Vue({
    data: { state }
  })
}
resetStoreVM 함수는 store에 _vm 속성을 추가하고state를 vue 대상의 데이터로 삼아 마지막으로 이 vue 대상을 에 부여하는 것이다vm.그래서 여기서 우리는 스토어류의 구조 함수에 하나를 추가했다는 것을 알게 되었다.vm 속성.
 
3.3 set 및 get
구조 함수 해석이 끝났고 다음에state와 관련된 방법을 계속 찾아야 하기 때문에 setget 방법을 찾았다.
get state () {
  return this._vm.state
}

set state (v) {
  assert(false, `Use store.replaceState() to explicit replace store state.`)
}
set 방법은 할 말이 없다. store가 직접 state를 수정하지 않는다는 뜻이다. (하지만 사실은 state 대상의 속성을 수정할 수 있다. 일단 그렇게 많은 것을 상관하지 않는다).get 방법은 방금 구조 함수에 추가된 를 되돌려줍니다vm 속성의 데이터 (state)여기까지 읽으면 구성 요소 a가state를 수정한 이유를 알 수 있습니다.count, 구성 요소 b도 따라서 변하겠지.state는 새로운 vue 대상에서 데이터의 속성이니까요.
 
4. 일반적인 API
4.1 commit 해석
컨디션을 바꿔야 한다면 보통commit을 사용하고commit 어떻게 컨디션의 변화를 실현하는지 살펴보자.
commit(_type, _payload, _options) {
  //        
  const { type, payload, options } = unifyObjectStyle(
    _type,
    _payload,
    _options
  )

  const mutation = { type, payload }
  //       mutation   
  const entry = this._mutations[type]
  //       
  if (!entry) {
    if (process.env.NODE_ENV !== 'production') {
      console.error(`[vuex] unknown mutation type: ${type}`)
    }
    return
  }
  // _withCommit     _committing
  //     TRUE,    strict    
  //    commit     
  this._withCommit(() => {
    entry.forEach(function commitIterator(handler) {
      // entry.push(function wrappedMutationHandler(payload) {
      //   handler.call(store, local.state, payload)
      // })
      // handle    wrappedMutationHandler   
      // wrappedMutationHandler       
      //     mutation   
      handler(payload)
    })
  })
  //       
  this._subscribers.forEach(sub => sub(mutation, this.state))
}
 
4.2 dispatch 분석
상태를 비동기적으로 바꾸는 것이 필요하다면 디스패치를 통해 이루어져야 한다.디스패치에서 호출된 commit 함수는 모두 다시 쓴 것으로 모듈 내의mutation 함수를 찾을 수 있습니다.
dispatch(_type, _payload) {
  //        
  const { type, payload } = unifyObjectStyle(_type, _payload)

  const action = { type, payload }
  //       action   
  const entry = this._actions[type]
  //       
  if (!entry) {
    if (process.env.NODE_ENV !== 'production') {
      console.error(`[vuex] unknown action type: ${type}`)
    }
    return
  }
  //       
  this._actionSubscribers.forEach(sub => sub(action, this.state))

  //     action    ,       
  //     promise,  promise   
  // resolve  ,     Promise.all
  //     
  return entry.length > 1
    ? Promise.all(entry.map(handler => handler(payload)))
    : entry[0](payload)
}
 
4.3 각종 문법 설탕
구성 요소에서 Vuex 기능을 정상적으로 사용하려면this.$store.state.xxx의 방식은 많은 불편을 가져왔다.이를 위해 Vuex는 문법사탕의 기능을 도입해 간단한 방식으로 상술한 기능을 실현할 수 있게 했다.다음은 맵State를 예로 들면 다른 몇 개의 맵은 차이가 많지 않은 원리이기 때문에 일일이 해석하지 않겠습니다.
function normalizeNamespace(fn) {
  return (namespace, map) => {
    //        
    //        namespace
    if (typeof namespace !== 'string') {
      map = namespace
      namespace = ''
    } else if (namespace.charAt(namespace.length - 1) !== '/') {
      namespace += '/'
    }
    return fn(namespace, map)
  }
}
//    mapState     
// normalizeNamespace      
export const mapState = normalizeNamespace((namespace, states) => {
  const res = {}
  // normalizeMap([1, 2, 3]) => [ { key: 1, val: 1 }, { key: 2, val: 2 }, { key: 3, val: 3 } ]
  // normalizeMap({a: 1, b: 2, c: 3}) => [ { key: 'a', val: 1 }, { key: 'b', val: 2 }, { key: 'c', val: 3 } ]
  // function normalizeMap(map) {
  //   return Array.isArray(map)
  //     ? map.map(key => ({ key, val: key }))
  //     : Object.keys(map).map(key => ({ key, val: map[key] }))
  // }
  // states               
  normalizeMap(states).forEach(({ key, val }) => {
    res[key] = function mappedState() {
      let state = this.$store.state
      let getters = this.$store.getters
      if (namespace) {
        //        
        const module = getModuleByNamespace(this.$store, 'mapState', namespace)
        if (!module) {
          return
        }
        state = module.context.state
        getters = module.context.getters
      }
      //    State
      return typeof val === 'function'
        ? val.call(this, state, getters)
        : state[val]
    }
    // mark vuex getter for devtools
    res[key].vuex = true
  })
  return res
})
 
다섯째, 총결산
이상은 Vuex의 원본 코드 해석입니다. Vuex의 전체 코드는 많지 않지만 읽을 만한 항목입니다.store의state를 알고 new를 통해 새로운 vue 대상임을 알았습니다vm가 감청하러 왔는데 이vm는 또store에 묶여있어요.그래서 이 일련의 관계를 통해, 마지막으로 우리는 각 구성 요소에서 감청된this.$를 사용할 수 있다store.state.
 
[관심 가져주시고 읽어주셔서 감사합니다. 후속 새로운 글 시작:sau 교류 학습 커뮤니티:https://www.mwcxs.top/】

좋은 웹페이지 즐겨찾기