Как мы все знаем,VuexдаFluxРеализация архитектуры. Flux четко устанавливает различные функциональные блоки в сценарии управления данными, и его основные принципы таковы:
- Централизованное государственное управление
- Статус может быть только специальным
突变
единица измерения - Прикладной уровень инициирует изменения, отправляя сигналы (обычно называемые действиями).
Vuex также разработан с учетом этих рекомендаций.store
Класс обеспечивает основные функции шаблона Flux. В дополнение к удовлетворению основных требований архитектуры дополнительно разработаны многие удобные меры:
- Изолируйте блоки данных с помощью «модульной» конструкции
- Обеспечьте механизм получения для улучшения возможности повторного использования кода.
- использовать
Vue.$watch
метод реализации потока данных - Нулевая конфигурация, естественно интегрированная в среду Vue
Аналитических статей в интернете уже много, так что повторяться нет нужды. Только эта статьяЦентрализация, сигнальный механизм, поток данныхРаскрывается реализация трех пунктов, обсуждаются дефекты реализации Vuex.
Центр
В Vuex,store
Он объединяет все функции, является основным внешним интерфейсом, а также центром управления данными в режиме Flux. Через него Vuex в основном обеспечивает:
- Связанные с сигналом:
dispatch、commit
- Интерфейс слушателя:
subscribe
- Интерфейс изменения значения состояния (заменяет значение состояния, не должен вызываться):
replaceState
- интерфейс изменения модели состояния (рекомендуется использовать только в эталонных сценариях по запросу):
registerModule、unregisterModule
- Интерфейс горячего обновления (HMRЛогика, не обращая внимания):
hotUpdate
официально реализованоstoreОчень сложный и в сочетании с большим количеством логики. Для краткости мы удалим все виды обходной логики и сосредоточимся только на архитектуре Flux.中心化
,信号控制
механизм, можно резюмировать очень простую реализацию:
export default class Store {
constructor(options) {
this._state = options.state;
this._mutations = options.mutations;
}
get state() {
return this._state;
}
commit(type, payload) {
this._mutations[type].apply(this, [this.state].concat([...payload]));
}
}
Это основа понимания Vuex, во всем коде всего две логики:
- пройти через
_state
Свойства для достижения уровня централизованного автономного центра обработки данных. - пройти через
dispatch
метод, обратный вызов запускает предварительно зарегистрированный_mutations
метод.
С этим кодом много проблем, например:
- Используйте простые объекты в качестве состояния
- Мутация состояния достигается только путем изменения значения свойства объекта состояния.
- Не существует эффективного механизма для предотвращения ошибочного изменения объекта состояния.
Эти проблемы дизайна также существуют в Vuex, который похож наVue.$watch
Механизм очень тесно связан (см. Ниже), что я лично нахожу крайне слабым.
сигнальный механизм
Vuex предоставляет два интерфейса, связанных с сигналами, и его исходный код можно сократить как:
export default class Store {
...
commit (_type, _payload, _options) {
...
const entry = this._mutations[type]
this._withCommit(() => {
entry.forEach(function commitIterator (handler) {
handler(payload)
})
})
this._subscribers.forEach(sub => sub(mutation, this.state))
...
}
dispatch (_type, _payload) {
...
const entry = this._actions[type]
return entry.length > 1
? Promise.all(entry.map(handler => handler(payload)))
: entry[0](payload)
}
...
}
Разница между ними заключается в следующем:
-
dispatch
срабатываетaction
Перезвоните;commit
запущенныйmutation
Перезвоните. -
dispatch
вернуть обещание;commit
Нет возвращаемого значения.
Этот замысел дизайна в основном касается разделения обязанностей, а единица действия используется для описаниячто случилось;mutationИспользуется для изменения состояния уровня данныхstate. Vuex использует похожие интерфейсы, чтобы разместить их в одном и том же месте, но на самом деле у этого уровня дизайна интерфейса есть недостатки:
- Для действия и мутации требуется система типов.
- Разрешить прикладному уровню напрямую обходить действие
commit
mutation - состояние не
immutable
, и разрешить изменение в действииstate
Хотя это и повышает удобство, но может привести к следующим антипаттернам для начинающих:
- Разработаны два набора систем типов, которые не могут быть ортогональными.
- Создает иллюзию «передачи мутации напрямую» и разрушает сигнальный механизм Flux.
- Состояние случайно изменяется в действии без дружественного механизма отслеживания (особенно это серьезно в геттере).
Поскольку не существует точного и эффективного механизма предотвращения ошибок, в процессе использования Vuex нужно быть очень бдительным, использовать различные функциональные блоки неукоснительно и правильно или использовать спецификации для восполнения недостатков дизайна.
Однонаправленный поток данных
Поток данных здесь относится к состоянию от Vuex до компонента Vue.props/computed/data
Отображение блока состояния, то есть как получить состояние в компоненте. Vuex официально рекомендуется использоватьmapGetter,mapStateИнтерфейс реализует привязку данных.
mapState
Функция очень проста, а логику кода можно представить так:
export const mapState = normalizeNamespace((namespace, states) => {
const res = {}
...
normalizeMap(states).forEach(({ key, val }) => {
res[key] = function mappedState() {
...
return typeof val === 'function' ?
val.call(this, state, getters) :
state[val]
}
})
...
return res
})
mapState напрямую считывает свойства объекта состояния. Стоит отметить, чтоres[key]
Как правило, она монтируется как функция во внешнем объекте.this
Указывает на смонтированный компонент Vue.
mapGetter
Функция также очень проста, и логика ее кода такова:
export const mapGetters = normalizeNamespace((namespace, getters) => {
const res = {}
normalizeMap(getters).forEach(({ key, val }) => {
res[key] = function mappedGetter() {
...
return this.$store.getters[val]
}
...
})
return res
})
mapGetter обращается к монтированию компонента$store
Свойство getters экземпляра.
из состояния в геттер
Свойство getter в Vuex во всех аспектах очень похоже на свойство вычисляемого в Vue.На самом деле, свойство получения реализовано на основе вычисленного. Его основная логика включает в себя:
function resetStoreVM(store, state, hot) {
...
store.getters = {}
const wrappedGetters = store._wrappedGetters
const computed = {}
// 遍历 getter 配置,生成 computed 属性
forEachValue(wrappedGetters, (fn, key) => {
computed[key] = () => fn(store)
Object.defineProperty(store.getters, key, {
// 获取 vue 实例属性
get: () => store._vm[key],
enumerable: true // for local getters
})
})
// 新建 Vue 实例,专门用于监听属性变更
store._vm = new Vue({
data: {
?state: state
},
computed
})
...
}
Как видно из кода, Vuex размещает весь объект состояния в свойстве данных экземпляра vue в обмен на все состояние Vue.watch
механизм. А свойство getter реализовано путем возврата вычисляемого свойства экземпляра, что не является тонким способом сделать это. Вопрос в том:
- Vuex тесно связан с Vue, что делает невозможным переход на другие среды.
- Вью
watch
Механизм реализован на основе функций чтения и записи атрибутов.Если корневой узел будет заменен напрямую, это приведет к сбою различных обратных вызовов субатрибутов, то есть невозможно будет достичьimmutable
характеристика
послесловие
Самое большое ощущение, которое вызывает у меня Vuex: удобство, одна и та же функция имеет множество логических единиц с разной семантикой, и разделение обязанностей очень хорошее.Если строго следовать спецификации, можно действительно очень хорошо организовать код; интерфейс тоже очень простой и удобный.Да, очень дружелюбный к разработчикам. С точки зрения количества пользователей, влияния и т. д., это, несомненно, очень хороший фреймворк. Конечно, некоторые из высказанных здесь мнений также имеют разные мнения, и цель их не более чем провокация других.