Kai*_*cui 173
问题1:为什么Vuejs开发人员决定这样做?
回答:
问题2:"行动"和"变异"之间有什么区别?
我们先来看官方解释:
突变:
Vuex突变本质上是事件:每个突变都有一个名称和一个处理程序.
Run Code Online (Sandbox Code Playgroud)import Vuex from 'vuex' const store = new Vuex.Store({ state: { count: 1 }, mutations: { INCREMENT (state) { // mutate state state.count++ } } })操作:操作只是调度突变的函数.
Run Code Online (Sandbox Code Playgroud)// the simplest action function increment (store) { store.dispatch('INCREMENT') } // a action with additional arguments // with ES2015 argument destructuring function incrementBy ({ dispatch }, amount) { dispatch('INCREMENT', amount) }
以下是我对上述内容的解释:
小智 52
变异是同步的,而动作可以是异步的.
换句话说:如果您的操作是同步的,则不需要操作,否则执行它们.
Mic*_*oka 16
我相信,了解“突变和动作”背后的动机可以使人们更好地判断何时使用哪种方式。在“规则”变得模糊的情况下,这也使程序员摆脱了不确定的负担。在对它们各自的用途进行了一些推理之后,我得出的结论是,尽管使用操作和变异的方法肯定是错误的,但我认为并没有一种规范的方法。
首先让我们尝试理解为什么我们甚至经历突变或动作。
为什么首先要通过样板?为什么不直接在组件中更改状态?
严格来说,您可以state直接从组件中更改。该state仅仅是一个JavaScript对象并没有什么神奇的,将还原更改,你做它。
// Yes, you can!
this.$store.state['products'].push(product)
Run Code Online (Sandbox Code Playgroud)
但是,通过这样做,您将在各处散布状态突变。您将失去仅打开包含状态的单个模块的能力,一目了然地看到可以对其执行何种操作。具有集中化的突变可以解决此问题,尽管要付出一些样板的代价。
// so we go from this
this.$store.state['products'].push(product)
// to this
this.$store.commit('addProduct', {product})
...
// and in store
addProduct(state, {product}){
state.products.push(product)
}
...
Run Code Online (Sandbox Code Playgroud)
我认为,如果您用样板替换一些短的东西,您会希望样板也要小。因此,我认为突变是针对状态本机操作的非常薄的包装,几乎没有业务逻辑。换句话说,突变意味着像塞特犬一样经常使用。
既然您已经集中了突变,就可以更好地了解状态变化,并且由于您的工具(vue-devtools)也知道该位置,因此使调试更加容易。还需要记住的是,许多Vuex的插件并不直接监视状态来跟踪更改,而是依赖于突变。因此,他们看不到状态的“越界”更改。
那么
mutations,actions到底有什么区别呢?
动作(如突变)也驻留在商店的模块中,并且可以接收state对象。这意味着,他们可能还直接发生变异它。那么,两者都具有什么意义呢?如果我们认为必须使变异保持小而简单,则意味着我们需要一种替代方法来容纳更详尽的业务逻辑。行动是做到这一点的手段。而且由于我们早先已经建立了,vue-devtools和插件知道通过Mutations进行的更改,为了保持一致,我们应该继续从操作中使用Mutations。此外,由于动作应包含所有内容,并且它们封装的逻辑可以是异步的,因此从一开始就将动作也简单地设为异步是有意义的。
人们经常强调动作可以是异步的,而变异通常不是异步的。您可能会决定将这种区别看作是对任何同步对象(对于任何异步对象,都应使用动作)的一种指示。但是,例如,如果您需要(同步)提交多个突变,或者需要使用突变中的Getter,则您会遇到一些困难,因为突变函数既不接受Getter也不接受Mutations作为参数。
...导致一个有趣的问题。
为什么突变不接受吸气剂?
对于这个问题,我还没有找到满意的答案。我已经看到核心团队的一些解释,认为我充其量是最好的。如果我总结一下它们的用法,则应该将Getter扩展为该状态的扩展(通常是缓存的)。换句话说,它们基本上仍然是状态,尽管需要进行一些前期计算,并且它们通常是只读的。至少这是鼓励它们被使用的方式。
因此,阻止Mutations直接访问Getters意味着,如果我们需要从前者访问后者提供的某些功能,那么现在有三件事之一是必要的:(1)Getter提供的状态计算要么在某个可以访问的地方重复进行,到Mutation(难闻的气味),或(2)将计算值(或相关的Getter本身)作为显式变元传递给Mutation(笨拙),或(3)Getter的逻辑本身直接在Mutation中重复,而没有Getter(恶臭)提供的缓存优势。
以下是(2)的示例,在我遇到的大多数情况下,它似乎都是“最差”的选项。
state:{
shoppingCart: {
products: []
}
},
getters:{
hasProduct(state){
return function(product) { ... }
}
}
actions: {
addProduct({state, getters, commit, dispatch}, {product}){
// all kinds of business logic goes here
// then pull out some computed state
const hasProduct = getters.hasProduct(product)
// and pass it to the mutation
commit('addProduct', {product, hasProduct})
}
}
mutations: {
addProduct(state, {product, hasProduct}){
if (hasProduct){
// mutate the state one way
} else {
// mutate the state another way
}
}
}
Run Code Online (Sandbox Code Playgroud)
在我看来,以上内容不仅令人费解,而且有些“漏水”,因为“动作”中存在的某些代码显然是从“变异”的内部逻辑中渗出的。
我认为,这表明存在妥协。我认为,允许Mutations自动接收Getters会带来一些挑战。它可以是Vuex本身的设计,也可以是工具(vue-devtools等)的设计,或者是保持一定的向后兼容性,或者是所有陈述的可能性的某种组合。
我不相信自己将Getters传递给您的Mutations必然表明您做错了事。我认为这只是“修补”框架的缺点之一。
小智 13
我认为TLDR的答案是Mutations意味着同步/事务性.因此,如果您需要运行Ajax调用或执行任何其他异步代码,则需要在Action中执行此操作,然后在设置新状态之后提交变异.
我已经专业地使用 Vuex 大约 3 年了,这就是我认为我已经弄清楚了 action 和 mutations 之间的本质区别,你如何从一起使用它们中受益,以及如果你可以让你的生活更艰难不好好用。
Vuex 的主要目标是提供一种新模式来控制应用程序的行为:反应性。这个想法是将应用程序状态的编排卸载到一个专门的对象:商店。它方便地提供了将您的组件直接连接到您的商店数据以方便使用的方法。这允许您的组件专注于它们的工作:定义模板、样式和基本组件行为以呈现给您的用户。同时,存储处理繁重的数据负载。
但这不仅仅是这种模式的唯一优势。存储是整个应用程序的单一数据源这一事实提供了跨多个组件重用这些数据的巨大潜力。这不是第一个尝试解决跨组件通信问题的模式,但它的亮点在于它通过基本上禁止组件修改此共享数据的状态来强制您对应用程序实施非常安全的行为,并强制它改为使用“公共端点”来请求更改。
基本思想是这样的:
话虽如此,当我们开始以这种方式设计我们的应用程序时,魔法就开始了。例如:
最后,我们有一种被视为“反应式”的用户体验。从我们用户的角度来看,该项目已被立即删除。大多数时候,我们希望我们的端点能够正常工作,所以这是完美的。当它失败时,我们仍然可以控制我们的应用程序将如何反应,因为我们已经成功地将前端应用程序的状态与实际数据的关注点分开了。
请注意,您并不总是需要商店。如果您发现您正在编写如下所示的商店:
export default {
state: {
orders: []
},
mutations: {
ADD_ORDER (state, order) {
state.orders.push(order)
},
DELETE_ORDER (state, orderToDelete) {
state.orders = state.orders.filter(order => order.id !== orderToDelete.id)
}
},
actions: {
addOrder ({commit}, order) {
commit('ADD_ORDER', order)
},
deleteOrder ({commit}, order) {
commit('DELETE_ORDER', order)
}
},
getters: {
orders: state => state.orders
}
}
Run Code Online (Sandbox Code Playgroud)
在我看来,您似乎只是将存储用作数据存储,并且可能错过了它的反应性方面,因为它不让它也控制您的应用程序响应的变量。基本上,您可以而且应该将在您的组件中编写的一些代码行卸载到您的商店。
突变:
Can update the state. (Having the Authorization to change the state).
Run Code Online (Sandbox Code Playgroud)
行动:
Actions are used to tell "which mutation should be triggered"
Run Code Online (Sandbox Code Playgroud)
以 Redux 方式
Run Code Online (Sandbox Code Playgroud)Mutations are Reducers Actions are Actions
为什么都是??
当应用程序增长时,编码和行数会增加,那个时候你必须处理 Actions 中的逻辑而不是突变,因为突变是改变状态的唯一权限,它应该尽可能干净。
免责声明 - 我刚开始使用vuejs所以这只是我推断设计意图.
时间机器调试使用状态的快照,并显示动作和突变的时间线.从理论上讲,我们可能只是actions记录状态设定者和吸气剂同步描述突变.但是之后:
mutations交易中,但我们可以说交易需要改进,而不是作为行动中的竞争条件.动作中的匿名突变可以更容易地重现这些类型的错误,因为异步编程是脆弱和困难的.将以下事务日志与命名突变进行比较.
Action: FetchNewsStories
Mutation: SetFetchingNewsStories
Action: FetchNewsStories [continuation]
Mutation: DoneFetchingNewsStories([...])
Run Code Online (Sandbox Code Playgroud)
使用没有命名突变的事务日志:
Action: FetchNewsStories
Mutation: state.isFetching = true;
Action: FetchNewsStories [continuation]
Mutation: state.isFetching = false;
Mutation: state.listOfStories = [...]
Run Code Online (Sandbox Code Playgroud)
我希望你能从这个例子中推断出行为中异步和匿名变异的潜在增加的复杂性.
https://vuex.vuejs.org/en/mutations.html
现在假设我们正在调试应用程序并查看devtool的变异日志.对于记录的每个突变,devtool将需要捕获状态的"之前"和"之后"快照.但是,上面示例变异中的异步回调使得这是不可能的:当提交变异时,回调函数尚未被调用,并且devtool无法知道何时实际调用回调 - 在回调中执行任何状态变异基本上是不可跟踪的!
根据 docs
行动类似于突变,不同之处在于:
请考虑以下代码段.
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++ //Mutating the state. Must be synchronous
}
},
actions: {
increment (context) {
context.commit('increment') //Committing the mutations. Can be asynchronous.
}
}
})
Run Code Online (Sandbox Code Playgroud)
操作处理程序(增量)接收一个上下文对象,该对象在商店实例上公开同一组方法/属性,因此您可以调用context.commit来提交变异,或者通过context.state和context.getters访问状态和getter.
动作和突变之间的主要区别是: