Vuex Action vs Đột biến


173

Trong Vuex, logic của việc có cả "hành động" và "đột biến là gì?"

Tôi hiểu logic của các thành phần không thể sửa đổi trạng thái (có vẻ thông minh), nhưng có cả hành động và đột biến có vẻ như bạn đang viết một hàm để kích hoạt chức năng khác, sau đó thay đổi trạng thái.

Sự khác biệt giữa "hành động" và "đột biến", làm thế nào để chúng hoạt động cùng nhau và moreso, tôi tò mò tại sao các nhà phát triển Vuex quyết định làm theo cách này?


2
Xem "Thực hiện hành động", tôi nghĩ: vuex.vuejs.org/en/mutations.html#on-to-ilities
Roy J

thảo luận liên quan: github.com/vuejs/vuex/issues/587
chuck911

1
Bạn không thể trực tiếp thay đổi trạng thái của cửa hàng. Cách duy nhất để thay đổi trạng thái của một cửa hàng là bằng cách cam kết rõ ràng các đột biến. Cho rằng chúng ta cần hành động để thực hiện các đột biến.
Suresh Sapkota

1
@SureshSapkota tuyên bố đó rất khó hiểu, vì cả hai mutationsactionsđược định nghĩa trong tài liệu vuex là phương pháp thay đổi trạng thái. Bạn không cần một hành động để gây đột biến.
Graham

1
Đột biến, như tên cho thấy được sử dụng để sửa đổi / biến đổi đối tượng trạng thái của bạn. Hành động khá giống với đột biến, nhưng thay vì đột biến trạng thái, Hành động lại gây đột biến. Các hành động có thể chứa bất kỳ mã không đồng bộ tùy ý hoặc logic nghiệp vụ . Vuex khuyến nghị đối tượng trạng thái chỉ nên được đột biến bên trong các hàm Đột biến. Bạn cũng không nên chạy bất kỳ mã nặng hoặc chặn nào bên trong các hàm Đột biến vì bản chất nó là đồng bộ .
Emmanuel Neni

Câu trả lời:


221

Câu hỏi 1 : Tại sao các nhà phát triển Vuejs quyết định làm theo cách này?

Câu trả lời:

  1. Khi ứng dụng của bạn trở nên lớn và khi có nhiều nhà phát triển làm việc trong dự án này, bạn sẽ thấy "quản lý trạng thái" (đặc biệt là "trạng thái toàn cầu"), sẽ ngày càng phức tạp hơn.
  2. Cách vuex (giống như Redux trong Reac.js ) cung cấp một cơ chế mới để quản lý trạng thái, giữ trạng thái và "lưu và theo dõi" (có nghĩa là mọi hành động sửa đổi trạng thái có thể được theo dõi bằng công cụ gỡ lỗi: vue-devtools )

Câu hỏi 2 : Sự khác biệt giữa "hành động" và "đột biến" là gì?

Trước tiên hãy xem lời giải thích chính thức:

Đột biến:

Đột biến Vuex thực chất là các sự kiện: mỗi đột biến có một tên và một trình xử lý.

import Vuex from 'vuex'

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    INCREMENT (state) {
      // mutate state
      state.count++
    }
  }
})

Hành động: Hành động chỉ là các chức năng gửi đột biến.

// 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)
}

Dưới đây là lời giải thích của tôi về những điều trên:

  • đột biếncách duy nhất để sửa đổi trạng thái
  • đột biến không quan tâm đến logic kinh doanh, nó chỉ quan tâm đến "trạng thái"
  • hành động là logic kinh doanh
  • hành động có thể gửi nhiều hơn 1 đột biến cùng một lúc, nó chỉ thực hiện logic nghiệp vụ, nó không quan tâm đến việc thay đổi dữ liệu (quản lý bằng đột biến)

80
Việc một hành động "là logic kinh doanh" và có thể gửi nhiều đột biến cùng một lúc là hữu ích. Đó là câu trả lời tôi đang tìm kiếm. Cảm ơn bạn.
Kobi

11
bạn cuys đang nói bạn "gửi một đột biến". Không phải là từ ngữ chính xác mà bạn CAM KẾT đột biến sao?
Vấn

4
Bạn gửi hành động và cam kết đột biến.
eirik

4
công văn không còn hoạt động trong vue 2.0 cho đột biến, bạn cần phải thực hiện một đột biến trong hành động.
SKLTFZ

18
@Komsui Câu trả lời này thiếu một lưu ý về các đột biến luôn luôn đồng bộ và các hành động có khả năng không đồng bộ. Ngoài ra, một câu trả lời tốt!
quyết định

58

Đột biến là đồng bộ, trong khi các hành động có thể không đồng bộ.

Để đặt nó theo một cách khác: bạn không cần hành động nếu các hoạt động của bạn là đồng bộ, nếu không thì thực hiện chúng.


2
điều này thực sự trả lời một câu hỏi tôi sẽ đưa ra, về cách ví dụ todomvc không sử dụng các hành động.
sksallaj

7
'Bạn không cần phải hành động nếu hoạt động của bạn được đồng bộ' : Đó là không đúng sự thật: bạn làm những hành động cần thiết nếu bạn muốn soạn nhiều đột biến từ các mô-đun cùng, bởi vì bạn không thể gọi một hành động từ một hành động.
Raymundus

1
Theo dõi rõ ràng cho câu trả lời này sẽ là "vậy thì tại sao không hành động và loại bỏ đột biến"
Michael Mrozek

34

Tôi tin rằng việc hiểu được các động lực đằng sau Đột biến và Hành động cho phép người ta đánh giá tốt hơn khi nào nên sử dụng cái nào và như thế nào. Nó cũng giải phóng lập trình viên khỏi gánh nặng của sự không chắc chắn trong các tình huống mà "quy tắc" trở nên mờ nhạt. Sau khi suy luận một chút về mục đích tương ứng của họ, tôi đã đi đến kết luận rằng mặc dù có thể có những cách sai để sử dụng Hành động và Đột biến, tôi không nghĩ rằng có một cách tiếp cận kinh điển.

Trước tiên chúng ta hãy cố gắng hiểu lý do tại sao chúng ta thậm chí trải qua cả Đột biến hoặc Hành động.

Tại sao đi qua lò hơi ở nơi đầu tiên? Tại sao không thay đổi trạng thái trực tiếp trong các thành phần?

Nói đúng ra bạn có thể thay đổi statetrực tiếp từ các thành phần của mình. Đây statechỉ là một đối tượng JavaScript và không có gì kỳ diệu sẽ hoàn nguyên các thay đổi mà bạn thực hiện đối với nó.

// Yes, you can!
this.$store.state['products'].push(product)

Tuy nhiên, bằng cách này, bạn đang phân tán các đột biến trạng thái của mình ở mọi nơi. Bạn mất khả năng chỉ đơn giản là mở một mô-đun duy nhất chứa trạng thái và trong nháy mắt xem loại hoạt động nào có thể được áp dụng cho nó. Có đột biến tập trung giải quyết điều này, mặc dù với chi phí của một số nồi hơi.

// 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)
}
...

Tôi nghĩ rằng nếu bạn thay thế một cái gì đó ngắn bằng nồi hơi, bạn sẽ muốn nồi hơi cũng nhỏ. Do đó, tôi cho rằng đột biến có nghĩa là các trình bao bọc rất mỏng xung quanh các hoạt động tự nhiên trên tiểu bang, gần như không có logic kinh doanh. Nói cách khác, đột biến có nghĩa là chủ yếu được sử dụng như setters.

Bây giờ bạn đã tập trung các đột biến của mình, bạn có cái nhìn tổng quan hơn về các thay đổi trạng thái của mình và vì công cụ của bạn (vue-devtools) cũng nhận thức được vị trí đó nên việc gỡ lỗi dễ dàng hơn. Cũng đáng lưu ý rằng nhiều plugin của Vuex không theo dõi trực tiếp trạng thái để theo dõi các thay đổi, họ thay vào đó dựa vào các đột biến cho điều đó. Do đó, những thay đổi "ngoài giới hạn" đối với nhà nước là vô hình đối với họ.

Vì vậy mutations, actionssự khác biệt là gì?

Các hành động, như đột biến, cũng nằm trong mô-đun của cửa hàng và có thể nhận stateđối tượng. Điều đó ngụ ý rằng họ cũng có thể đột biến nó trực tiếp. Vậy quan điểm của việc có cả hai là gì? Nếu chúng ta lý do rằng các đột biến phải được giữ nhỏ và đơn giản, điều đó có nghĩa là chúng ta cần một phương tiện thay thế để chứa logic kinh doanh phức tạp hơn. Hành động là phương tiện để làm điều này. Và vì như chúng tôi đã thiết lập trước đó, vue-devtools và plugin nhận thức được các thay đổi thông qua Đột biến, để duy trì sự nhất quán, chúng tôi nên tiếp tục sử dụng Đột biến từ hành động của mình. Hơn nữa, vì các hành động có nghĩa là bao gồm tất cả và logic mà chúng gói gọn có thể không đồng bộ, nên có nghĩa là Hành động cũng sẽ đơn giản được thực hiện không đồng bộ ngay từ đầu.

Người ta thường nhấn mạnh rằng các hành động có thể không đồng bộ, trong khi các đột biến thường không xảy ra. Bạn có thể quyết định xem sự khác biệt như một dấu hiệu cho thấy các đột biến nên được sử dụng cho bất kỳ điều gì đồng bộ (và hành động cho bất kỳ điều gì không đồng bộ); tuy nhiên, bạn sẽ gặp một số khó khăn nếu bạn cần phải thực hiện nhiều hơn một đột biến (đồng bộ) hoặc nếu bạn cần làm việc với Getter từ các đột biến của mình, vì các hàm đột biến không nhận được Getters cũng như Đột biến làm đối số ...

... dẫn đến một câu hỏi thú vị.

Tại sao Đột biến không nhận được Getters?

Tôi chưa tìm thấy câu trả lời thỏa đáng cho câu hỏi này. Tôi đã thấy một số lời giải thích của nhóm nòng cốt mà tôi thấy tốt nhất. Nếu tôi tóm tắt cách sử dụng của chúng, Getters có nghĩa là các phần mở rộng được tính toán (và thường được lưu trong bộ nhớ cache) về trạng thái. Nói cách khác, về cơ bản chúng vẫn là trạng thái, mặc dù đòi hỏi một số tính toán trả trước và chúng thường chỉ đọc. Đó ít nhất là cách họ được khuyến khích sử dụng.

Do đó, ngăn chặn Đột biến truy cập trực tiếp vào Getters có nghĩa là một trong ba điều cần thiết bây giờ, nếu chúng ta cần truy cập từ một số chức năng trước đây được cung cấp bởi sau: (1) các tính toán trạng thái do Getter cung cấp được sao chép ở đâu đó có thể truy cập được đối với Đột biến (mùi hôi) hoặc (2) giá trị được tính toán (hoặc chính Getter có liên quan) được truyền lại dưới dạng đối số rõ ràng đối với Đột biến (funky) hoặc (3) chính logic của Getter được sao chép trực tiếp trong Đột biến , không có thêm lợi ích của bộ nhớ đệm như được cung cấp bởi Getter (mùi hôi thối).

Sau đây là một ví dụ về (2), trong hầu hết các kịch bản mà tôi gặp phải có vẻ là tùy chọn "ít tệ nhất".

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 
        }
    }
}

Đối với tôi, những điều trên dường như không chỉ hơi phức tạp, mà còn hơi "rò rỉ", vì một số mã có trong Hành động rõ ràng được tiết lộ từ logic bên trong của Đột biến.

Theo tôi, đây là một dấu hiệu của sự thỏa hiệp. Tôi tin rằng việc cho phép Đột biến tự động nhận Getters đưa ra một số thách thức. Nó có thể là do thiết kế của Vuex, hoặc dụng cụ (vue-devtools et al), hoặc để duy trì một số khả năng tương thích ngược, hoặc kết hợp tất cả các khả năng đã nêu.

Điều tôi không tin là việc tự mình chuyển Getters cho Đột biến của bạn nhất thiết là một dấu hiệu cho thấy bạn đang làm gì đó sai. Tôi thấy nó chỉ đơn giản là "vá" một trong những thiếu sót của khung.


1
Đối với tôi đó là câu trả lời tốt nhất. Chỉ sau khi đọc nó, tôi mới có "cú nhấp" này khi bạn cảm thấy bạn hiểu điều gì đó.
Robert Kusznier

Getters về cơ bản là computedđầu ra. Họ chỉ đọc. Một cách đẹp hơn để xem các đột biến có thể là loại bỏ những if elsegì bạn có. Các tài liệu vuex nói rằng bạn có thể chứa nhiều hơn 1 committrong một hành động. Vì vậy, sẽ là hợp lý khi cho rằng bạn có thể thực hiện một số đột biến nhất định tùy thuộc vào logic. Tôi xem các hành động như là một cách để ra lệnh đột biến lửa.
Tamb

@Tamb: Bang và Getters đều cung cấp dữ liệu theo ngữ cảnh. Nó có ý nghĩa rằng họ sẽ được truy vấn trước khi quyết định sửa đổi Nhà nước. Khi thông tin đó có thể được lấy hoàn toàn từ Trạng thái, điều đó có nghĩa là toàn bộ logic được gói gọn trong một Đột biến duy nhất, vì nó có quyền truy cập vào Trạng thái. Đây là quy trình vận hành tiêu chuẩn cho một setter. Điều có ý nghĩa ít hơn là có một cách tiếp cận hoàn toàn khác chỉ đơn giản vì bây giờ chúng ta cần truy vấn một Getter để có thông tin tương tự.
Michael Ekoka

@Tamb: Điều bạn gợi ý là khi cần truy vấn Getters, chúng ta nên thay đổi mẫu trên và di chuyển logic lựa chọn sang Hành động proxy có thể truy cập Getter và có thể kết dính một loạt các Đột biến câm nhỏ. Nó hoạt động, nhưng nó vẫn có mạch và không giải quyết được mùi hôi mà tôi đang đề cập đến trong câu trả lời của mình, nó chỉ di chuyển nó đến một nơi khác.
Michael Ekoka

Các tài liệu nói rằng để sử dụng getters khi bạn cần tính toán trạng thái. Vì vậy, nó có vẻ đúng cho đến ngày chúng tương tự như các thuộc tính được tính toán. Idk những gì bạn đang nhận được bằng cách nói hành động có thể kết dính các đột biến. Các tài liệu nói rõ ràng để đưa logic kinh doanh vào bên trong các hành động.
Tamb

15

Tôi nghĩ rằng câu trả lời của TLDR là Đột biến có nghĩa là đồng bộ / giao dịch. Vì vậy, nếu bạn cần chạy một cuộc gọi Ajax hoặc thực hiện bất kỳ mã không đồng bộ nào khác, bạn cần thực hiện điều đó trong một Hành động và sau đó thực hiện một đột biến sau, để đặt trạng thái mới.


1
Điều này trông giống như một bản tóm tắt của tài liệu; không có gì sai với Tuy nhiên, vấn đề với câu trả lời này là những gì nó khẳng định không nhất thiết là đúng. Bạn CÓ THỂ sửa đổi trạng thái bên trong đột biến khi gọi hàm không đồng bộ / AJAX, sau đó có thể được thay đổi trong cuộc gọi lại hoàn chỉnh. Tôi nghĩ rằng đây là điều gây ra nhiều nhầm lẫn về lý do tại sao các hành động nên được sử dụng cho các hoạt động phát triển tốt nhất khi làm việc với Vuex. Tôi biết đó chắc chắn là một nguồn gây nhầm lẫn cho tôi khi tôi bắt đầu làm việc với Vuex.
Erutan409

8

Sự khác biệt chính giữa Hành động và Đột biến:

  1. Hành động bên trong bạn có thể chạy mã không đồng bộ nhưng không đột biến. Vì vậy, sử dụng các hành động cho mã không đồng bộ nếu không sử dụng các đột biến.
  2. Bên trong các hành động bạn có thể truy cập getters, trạng thái, đột biến (cam kết chúng), hành động (gửi chúng) trong các đột biến bạn có thể truy cập vào trạng thái. Vì vậy, nếu bạn muốn truy cập chỉ nhà nước sử dụng các đột biến nếu không sử dụng các hành động.

5

Theo docs

Hành động tương tự như đột biến , sự khác biệt là:

  • Thay vì đột biến trạng thái, hành động gây đột biến.
  • Các hành động có thể chứa các hoạt động không đồng bộ tùy ý .

Hãy xem xét đoạn trích sau.

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.
    }
  }
})

Trình xử lý hành động ( gia tăng ) nhận một đối tượng ngữ cảnh hiển thị cùng một tập hợp các phương thức / thuộc tính trên cá thể cửa hàng, vì vậy bạn có thể gọi context.commit để thực hiện một đột biến hoặc truy cập trạng thái và getters thông qua bối cảnh.state và bối cảnh.


1
là cuộc gọi khả thi từ chức năng 'đột biến', một phương thức từ thành phần vuejs?
Alberto Acuña

@ AlbertoAcuña Tôi có cùng một câu hỏi, bởi vì khi tôi thử làm điều đó, nó sẽ đưa ra một lỗi mà đột biến cục bộ không được xác định.
Rutwick Gangurde

5

Tuyên bố miễn trừ trách nhiệm - Tôi mới chỉ bắt đầu sử dụng vuejs nên đây chỉ là tôi ngoại suy ý định thiết kế.

Gỡ lỗi cỗ máy thời gian sử dụng ảnh chụp nhanh của trạng thái và hiển thị dòng thời gian của hành động và đột biến. Về lý thuyết, chúng ta có thể đã có actionscùng với một bản ghi các setters và getters trạng thái để mô tả đồng bộ đột biến. Nhưng sau đó:

  • Chúng tôi sẽ có đầu vào không tinh khiết (kết quả không đồng bộ) gây ra setters và getters. Điều này sẽ khó theo dõi một cách hợp lý và các setters và getters async khác nhau có thể tương tác đáng ngạc nhiên. Điều đó vẫn có thể xảy ra với mutationscác giao dịch nhưng sau đó chúng ta có thể nói rằng giao dịch cần phải được cải thiện chứ không phải là một điều kiện chạy đua trong các hành động. Các đột biến ẩn danh bên trong một hành động có thể dễ dàng tái hiện các loại lỗi này vì lập trình async rất mong manh và khó khăn.
  • Nhật ký giao dịch sẽ khó đọc vì sẽ không có tên cho các thay đổi trạng thái. Nó sẽ giống như nhiều mã hơn và ít tiếng Anh hơn, thiếu các nhóm đột biến logic.
  • Nó có thể phức tạp hơn và ít hiệu quả hơn đối với công cụ ghi lại bất kỳ đột biến nào trên một đối tượng dữ liệu, trái ngược với bây giờ khi có các điểm khác biệt được xác định đồng bộ - trước và sau khi gọi hàm đột biến. Tôi không chắc vấn đề đó lớn đến mức nào.

So sánh nhật ký giao dịch sau đây với các đột biến được đặt tên.

Action: FetchNewsStories
Mutation: SetFetchingNewsStories
Action: FetchNewsStories [continuation]
Mutation: DoneFetchingNewsStories([...])

Với nhật ký giao dịch không có đột biến có tên:

Action: FetchNewsStories
Mutation: state.isFetching = true;
Action: FetchNewsStories [continuation]
Mutation: state.isFetching = false;
Mutation: state.listOfStories = [...]

Tôi hy vọng bạn có thể ngoại suy từ ví dụ đó về sự phức tạp được thêm vào trong sự không đồng bộ và đột biến ẩn danh bên trong các hành động.

https://vuex.vuejs.org/en/mutations.html

Bây giờ hãy tưởng tượng chúng ta đang gỡ lỗi ứng dụng và xem nhật ký đột biến của devtool. Đối với mỗi đột biến được ghi lại, devtool sẽ cần chụp các ảnh chụp nhanh "trước" và "sau" của trạng thái. Tuy nhiên, cuộc gọi lại không đồng bộ bên trong đột biến ví dụ ở trên khiến điều đó trở nên không thể: cuộc gọi lại chưa được gọi khi đột biến được thực hiện và không có cách nào để devtool biết khi nào cuộc gọi lại thực sự sẽ được gọi - bất kỳ đột biến trạng thái nào được thực hiện trong cuộc gọi lại về cơ bản là không thể theo dõi!


4

Đột biến:

Can update the state. (Having the Authorization to change the state).

Hành động:

Actions are used to tell "which mutation should be triggered"

Theo cách Redux

Mutations are Reducers
Actions are Actions

Tại sao cả hai ??

Khi ứng dụng phát triển, mã hóa và các dòng sẽ tăng lên, Lúc đó bạn phải xử lý logic trong Hành động không phải trong các đột biến vì đột biến là cơ quan duy nhất thay đổi trạng thái, nó phải sạch nhất có thể.


2

Điều này làm tôi bối rối quá nên tôi đã làm một bản demo đơn giản.

thành phần.vue

<template>
    <div id="app">
        <h6>Logging with Action vs Mutation</h6>
        <p>{{count}}</p>
        <p>
            <button @click="mutateCountWithAsyncDelay()">Mutate Count directly with delay</button>
        </p>
        <p>
            <button @click="updateCountViaAsyncAction()">Update Count via action, but with delay</button>
        </p>
        <p>Note that when the mutation handles the asynchronous action, the "log" in console is broken.</p>
        <p>When mutations are separated to only update data while the action handles the asynchronous business
            logic, the log works the log works</p>
    </div>
</template>

<script>

        export default {
                name: 'app',

                methods: {

                        //WRONG
                        mutateCountWithAsyncDelay(){
                                this.$store.commit('mutateCountWithAsyncDelay');
                        },

                        //RIGHT
                        updateCountViaAsyncAction(){
                                this.$store.dispatch('updateCountAsync')
                        }
                },

                computed: {
                        count: function(){
                                return this.$store.state.count;
                        },
                }

        }
</script>

store.js

import 'es6-promise/auto'
import Vuex from 'vuex'
import Vue from 'vue';

Vue.use(Vuex);

const myStore = new Vuex.Store({
    state: {
        count: 0,
    },
    mutations: {

        //The WRONG way
        mutateCountWithAsyncDelay (state) {
            var log1;
            var log2;

            //Capture Before Value
            log1 = state.count;

            //Simulate delay from a fetch or something
            setTimeout(() => {
                state.count++
            }, 1000);

            //Capture After Value
            log2 = state.count;

            //Async in mutation screws up the log
            console.log(`Starting Count: ${log1}`); //NRHG
            console.log(`Ending Count: ${log2}`); //NRHG
        },

        //The RIGHT way
        mutateCount (state) {
            var log1;
            var log2;

            //Capture Before Value
            log1 = state.count;

            //Mutation does nothing but update data
            state.count++;

            //Capture After Value
            log2 = state.count;

            //Changes logged correctly
            console.log(`Starting Count: ${log1}`); //NRHG
            console.log(`Ending Count: ${log2}`); //NRHG
        }
    },

    actions: {

        //This action performs its async work then commits the RIGHT mutation
        updateCountAsync(context){
            setTimeout(() => {
                context.commit('mutateCount');
            }, 1000);
        }
    },
});

export default myStore;

Sau khi nghiên cứu điều này, kết luận mà tôi đưa ra là đột biến là một quy ước chỉ tập trung vào việc thay đổi dữ liệu để phân tách mối quan tâm tốt hơn và cải thiện việc ghi nhật ký trước và sau khi dữ liệu được cập nhật. Trong khi đó các hành động là một lớp trừu tượng xử lý logic mức cao hơn và sau đó gọi các đột biến một cách thích hợp


0

1.Từ tài liệu :

Hành động tương tự như đột biến, sự khác biệt là:

  • Thay vì đột biến trạng thái, hành động gây đột biến.
  • Các hành động có thể chứa các hoạt động không đồng bộ tùy ý.

Các hành động có thể chứa các hoạt động không đồng bộ, nhưng đột biến thì không thể.

2.Chúng tôi gọi đột biến, chúng tôi có thể thay đổi trạng thái trực tiếp. và chúng ta cũng có thể thay đổi trạng thái bằng cách này:

actions: {
  increment (store) {
    // do whatever ... then change the state
    store.dispatch('MUTATION_NAME')
  }
}

Các hành động được thiết kế để xử lý nhiều thứ khác, chúng ta có thể thực hiện nhiều việc trong đó (chúng ta có thể sử dụng các hoạt động không đồng bộ) sau đó thay đổi trạng thái bằng cách gửi đột biến ở đó.


0

Bởi vì không có nhà nước mà không có đột biến! Khi được cam kết - một phần logic, thay đổi trạng thái theo cách có thể thấy trước, sẽ được thực thi. Đột biến là cách duy nhất để thiết lập hoặc thay đổi trạng thái (vì vậy không có thay đổi trực tiếp!) Và hơn nữa - chúng phải đồng bộ. Giải pháp này thúc đẩy một chức năng rất quan trọng: các đột biến đang đăng nhập vào devtools. Và điều đó cung cấp cho bạn một khả năng đọc và dự đoán tuyệt vời!

Một điều nữa - hành động. Như đã nói - hành động gây đột biến. Vì vậy, họ không thay đổi cửa hàng và không cần phải đồng bộ hóa các cửa hàng này. Nhưng, họ có thể quản lý thêm một phần logic không đồng bộ!


0

Có vẻ như không cần thiết phải có thêm một lớp actionschỉ để gọi mutations, ví dụ:

const actions = {
  logout: ({ commit }) => {
    commit("setToken", null);
  }
};

const mutations = {
  setToken: (state, token) => {
    state.token = token;
  }
};

Vì vậy, nếu gọi actionscác cuộc gọi logout, tại sao không gọi chính đột biến?

Toàn bộ ý tưởng của một hành động là gọi nhiều đột biến từ bên trong một hành động hoặc thực hiện một yêu cầu Ajax hoặc bất kỳ loại logic không đồng bộ nào bạn có thể tưởng tượng.

Cuối cùng chúng ta có thể có các hành động thực hiện nhiều yêu cầu mạng và cuối cùng gọi nhiều đột biến khác nhau.

Vì vậy, chúng tôi cố gắng thứ càng nhiều phức tạp từ chúng tôi Vuex.Store()càng tốt trong của chúng tôi actionslá và điều này chúng tôi mutations, stategetterssạch hơn và dễ hiểu và rơi phù hợp với các loại mô đun mà làm cho thư viện như Vue và Phản ứng phổ biến.


0

Tôi đã sử dụng Vuex một cách chuyên nghiệp được khoảng 3 năm và đây là những gì tôi nghĩ rằng tôi đã tìm ra sự khác biệt cơ bản giữa hành động và đột biến, làm thế nào bạn có thể hưởng lợi từ việc sử dụng chúng cùng nhau và làm thế nào bạn có thể làm cho cuộc sống của bạn khó khăn hơn nếu bạn không sử dụng nó tốt.

Mục tiêu chính của Vuex là đưa ra một mô hình mới để kiểm soát hành vi của ứng dụng của bạn: Tính phản ứng. Ý tưởng là giảm tải sự phối hợp trạng thái của ứng dụng của bạn cho một đối tượng chuyên biệt: một cửa hàng. Nó thuận tiện cung cấp các phương thức để kết nối các thành phần của bạn trực tiếp với dữ liệu cửa hàng của bạn để sử dụng một cách thuận tiện. Điều này cho phép các thành phần của bạn tập trung vào công việc của chúng: xác định mẫu, kiểu và hành vi thành phần cơ bản để trình bày cho người dùng của bạn. Trong khi đó, cửa hàng xử lý tải dữ liệu nặng.

Đó không chỉ là lợi thế duy nhất của mẫu này. Thực tế là các cửa hàng là một nguồn dữ liệu duy nhất cho toàn bộ ứng dụng của bạn cung cấp tiềm năng lớn về khả năng sử dụng lại dữ liệu này trên nhiều thành phần. Đây không phải là mô hình đầu tiên cố gắng giải quyết vấn đề giao tiếp giữa các thành phần này, nhưng điều đáng nói là nó buộc bạn phải thực hiện một hành vi rất an toàn cho ứng dụng của mình bằng cách cơ bản cấm các thành phần của bạn sửa đổi trạng thái của dữ liệu được chia sẻ này và buộc nó thay vào đó sử dụng "điểm cuối công cộng" để yêu cầu thay đổi.

Ý tưởng cơ bản là thế này:

  • Cửa hàng có trạng thái nội bộ, không bao giờ được truy cập trực tiếp bởi các thành phần (mapState bị cấm một cách hiệu quả)
  • Cửa hàng có đột biến, đó là sửa đổi đồng bộ với trạng thái nội bộ. Công việc duy nhất của đột biến là sửa đổi trạng thái. Họ chỉ nên được gọi từ một hành động. Chúng nên được đặt tên để mô tả những điều đã xảy ra với trạng thái (ORDER_CANCELED, ORDER_CREATED). Giữ chúng ngắn và ngọt ngào. Bạn có thể bước qua chúng bằng cách sử dụng tiện ích mở rộng trình duyệt Vue Devtools (cũng rất tốt để gỡ lỗi!)
  • Cửa hàng cũng có các hành động, không đồng bộ hoặc trả lại lời hứa. Chúng là các hành động mà các thành phần của bạn sẽ gọi khi chúng muốn sửa đổi trạng thái của ứng dụng. Chúng nên được đặt tên với các hành động định hướng kinh doanh (động từ, ví dụ như CancOrder, createdOrder). Đây là nơi bạn xác nhận và gửi yêu cầu của bạn. Mỗi hành động có thể gọi các cam kết khác nhau ở bước khác nhau nếu được yêu cầu thay đổi trạng thái.
  • Cuối cùng, cửa hàng có getters, đó là những gì bạn sử dụng để hiển thị trạng thái của bạn với các thành phần của bạn. Hy vọng chúng sẽ được sử dụng nhiều trên nhiều thành phần khi ứng dụng của bạn mở rộng. Vuex lưu trữ rất nhiều getters để tránh các chu trình tính toán vô dụng (miễn là bạn không thêm tham số vào trình getter của mình - cố gắng không sử dụng tham số), vì vậy đừng ngần ngại sử dụng chúng rộng rãi. Chỉ cần đảm bảo rằng bạn đặt tên mô tả càng gần càng tốt trạng thái của ứng dụng hiện tại.

Điều đó đang được nói, phép thuật bắt đầu khi chúng ta bắt đầu thiết kế ứng dụng của mình theo cách này. Ví dụ:

  • Chúng tôi có một thành phần cung cấp danh sách các đơn đặt hàng cho người dùng với khả năng xóa các đơn hàng đó
  • Các thành phần đã ánh xạ một getter lưu trữ (deletableOrder), là một mảng các đối tượng có id
  • Thành phần này có một nút trên mỗi hàng của đơn đặt hàng và nhấp chuột của nó được ánh xạ tới hành động lưu trữ (removeOrder) để chuyển đối tượng đặt hàng đến nó (mà chúng ta sẽ nhớ, xuất phát từ chính danh sách của cửa hàng)
  • Cửa hàng xóa hành động thực hiện như sau:
    • nó xác nhận việc xóa
    • nó lưu trữ để xóa tạm thời
    • nó cam kết đột biến ORDER_DELETED với đơn đặt hàng
    • nó sẽ gửi lệnh gọi API để thực sự xóa thứ tự (vâng, SAU khi sửa đổi trạng thái!)
    • nó chờ cuộc gọi kết thúc (trạng thái đã được cập nhật) và khi thất bại, chúng tôi gọi đột biến ORDER_DELETE_FAILED với thứ tự chúng tôi đã giữ trước đó.
  • Đột biến ORDER_DELETED sẽ chỉ xóa đơn hàng đã cho khỏi danh sách các đơn hàng có thể xóa (sẽ cập nhật getter)
  • Đột biến ORDER_DELETE_FAILED chỉ cần đặt lại và sửa đổi trạng thái để thông báo lỗi (một thành phần khác, thông báo lỗi, sẽ theo dõi trạng thái đó để biết khi nào sẽ hiển thị chính nó)

Cuối cùng, chúng tôi có trải nghiệm người dùng được coi là "phản ứng". Từ quan điểm của người dùng của chúng tôi, các mục đã bị xóa ngay lập tức. Hầu hết thời gian, chúng tôi hy vọng các điểm cuối của chúng tôi chỉ hoạt động, vì vậy điều này là hoàn hảo. Khi thất bại, chúng tôi vẫn có một số kiểm soát về cách ứng dụng của chúng tôi sẽ phản ứng , bởi vì chúng tôi đã tách thành công mối quan tâm về trạng thái của ứng dụng giao diện người dùng của chúng tôi với dữ liệu thực tế.

Bạn không phải lúc nào cũng cần một cửa hàng, nhớ bạn. Nếu bạn thấy rằng bạn đang viết các cửa hàng trông như thế này:

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
  }
}

Đối với tôi có vẻ như bạn chỉ sử dụng cửa hàng làm kho lưu trữ dữ liệu và có lẽ đang bỏ lỡ khía cạnh phản ứng của nó, bằng cách không để nó cũng kiểm soát các biến mà ứng dụng của bạn phản ứng. Về cơ bản, bạn có thể và có thể giảm tải một số dòng mã được viết trong các thành phần của bạn cho các cửa hàng của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.