<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # Vuex > 原文:[https://docs.gitlab.com/ee/development/fe_guide/vuex.html](https://docs.gitlab.com/ee/development/fe_guide/vuex.html) * [Separation of concerns](#separation-of-concerns) * [File structure](#file-structure) * [`index.js`](#indexjs) * [`state.js`](#statejs) * [Access `state` properties](#access-state-properties) * [`actions.js`](#actionsjs) * [Dispatching actions](#dispatching-actions) * [`mutations.js`](#mutationsjs) * [Naming Pattern: `REQUEST` and `RECEIVE` namespaces](#naming-pattern-request-and-receive-namespaces) * [Updating complex state](#updating-complex-state) * [`getters.js`](#gettersjs) * [`mutation_types.js`](#mutation_typesjs) * [Initializing a store’s state](#initializing-a-stores-state) * [Why not just …spread the initial state?](#why-not-just-spread-the-initial-state) * [Communicating with the Store](#communicating-with-the-store) * [Vuex Gotchas](#vuex-gotchas) * [Testing Vuex](#testing-vuex) * [Testing Vuex concerns](#testing-vuex-concerns) * [Testing components that need a store](#testing-components-that-need-a-store) * [Two way data binding](#two-way-data-binding) # Vuex[](#vuex "Permalink") 如果將狀態管理與組件分離有明顯的好處(例如,由于狀態復雜性),我們建議使用[Vuex 而](https://vuex.vuejs.org)不是其他任何 Flux 模式. 否則,請隨時管理組件中的狀態. 在以下情況下,應強烈考慮 Vuex: * 您期望應用程序的多個部分對狀態變化做出反應 * 需要在多個組件之間共享數據 * 與后端的交互非常復雜,例如多個 API 調用 * 該應用程序涉及通過傳統 REST API 和 GraphQL 與后端進行交互(尤其是將 REST API 移至 GraphQL 時,這是一項待處理的后端任務) *注意:以下*所有內容在[Vuex](https://vuex.vuejs.org)官方[文檔](https://vuex.vuejs.org)中有更詳細的[說明](https://vuex.vuejs.org) . ## Separation of concerns[](#separation-of-concerns "Permalink") Vuex 由狀態,獲取器,變異,動作和模塊組成. 當用戶點擊一個動作時,我們需要`dispatch`它. 此操作將`commit`將更改狀態的突變. *注意:*動作本身不會更新狀態,只有突變可以更新狀態. ## File structure[](#file-structure "Permalink") 在 GitLab 上使用 Vuex 時,請將這些問題分為不同的文件以提高可讀性: ``` └── store ├── index.js # where we assemble modules and export the store ├── actions.js # actions ├── mutations.js # mutations ├── getters.js # getters ├── state.js # state └── mutation_types.js # mutation types ``` 下例顯示了一個列出用戶并將其添加到狀態的應用程序. (有關更復雜的示例實現,請查看[此處](https://gitlab.com/gitlab-org/gitlab/tree/master/ee/app/assets/javascripts/vue_shared/security_reports/store)的安全應用程序商店) ### `index.js`[](#indexjs "Permalink") 這是我們商店的入口點. 您可以使用以下內容作為指導: ``` import Vuex from 'vuex'; import * as actions from './actions'; import * as getters from './getters'; import mutations from './mutations'; import state from './state'; export const createStore = () => new Vuex.Store({ actions, getters, mutations, state, }); ``` *注意:*在實施此[RFC](https://gitlab.com/gitlab-org/frontend/rfcs/-/issues/20)之前,以上內容將需要禁用`import/prefer-default-export` ESLint 規則. ### `state.js`[](#statejs "Permalink") 在編寫任何代碼之前,您應該做的第一件事就是設計狀態. 通常,我們需要將數據從 haml 提供給 Vue 應用程序. 讓我們將其存儲在狀態中以便更好地訪問. ``` export default () => ({ endpoint: null, isLoading: false, error: null, isAddingUser: false, errorAddingUser: false, users: [], }); ``` #### Access `state` properties[](#access-state-properties "Permalink") 您可以使用`mapState`訪問組件中的狀態屬性. ### `actions.js`[](#actionsjs "Permalink") An action is a payload of information to send data from our application to our store. 動作通常由`type`和`payload` ,它們描述發生了什么. 與[變種](#mutationsjs)不同,動作可以包含異步操作-這就是為什么我們始終需要在動作中處理異步邏輯. 在此文件中,我們將編寫將調用突變的操作以處理用戶列表: ``` import * as types from './mutation_types'; import axios from '~/lib/utils/axios_utils'; import createFlash from '~/flash'; export const fetchUsers = ({ state, dispatch }) => { commit(types.REQUEST_USERS); axios.get(state.endpoint) .then(({ data }) => commit(types.RECEIVE_USERS_SUCCESS, data)) .catch((error) => { commit(types.RECEIVE_USERS_ERROR, error) createFlash('There was an error') }); } export const addUser = ({ state, dispatch }, user) => { commit(types.REQUEST_ADD_USER); axios.post(state.endpoint, user) .then(({ data }) => commit(types.RECEIVE_ADD_USER_SUCCESS, data)) .catch((error) => commit(types.REQUEST_ADD_USER_ERROR, error)); } ``` #### Dispatching actions[](#dispatching-actions "Permalink") 要從組件調度動作,請使用`mapActions`幫助器: ``` import { mapActions } from 'vuex'; { methods: { ...mapActions([ 'addUser', ]), onClickUser(user) { this.addUser(user); }, }, }; ``` ### `mutations.js`[](#mutationsjs "Permalink") 變異指定應用程序狀態如何響應發送到商店的操作而改變. 更改 Vuex 存儲中狀態的唯一方法應該是通過提交突變. **在編寫任何代碼之前先考慮狀態是一個好主意.** 請記住,動作僅描述發生了某些事情,而沒有描述應用程序狀態如何變化. **切勿直接從組件提交突變** 相反,您應該創建一個將導致突變的動作. ``` import * as types from './mutation_types'; export default { [types.REQUEST_USERS](state) { state.isLoading = true; }, [types.RECEIVE_USERS_SUCCESS](state, data) { // Do any needed data transformation to the received payload here state.users = data; state.isLoading = false; }, [types.RECEIVE_USERS_ERROR](state, error) { state.isLoading = false; }, [types.REQUEST_ADD_USER](state, user) { state.isAddingUser = true; }, [types.RECEIVE_ADD_USER_SUCCESS](state, user) { state.isAddingUser = false; state.users.push(user); }, [types.REQUEST_ADD_USER_ERROR](state, error) { state.isAddingUser = false; state.errorAddingUser = error; }, }; ``` #### Naming Pattern: `REQUEST` and `RECEIVE` namespaces[](#naming-pattern-request-and-receive-namespaces "Permalink") 發出請求時,我們通常希望向用戶顯示加載狀態. 與其創建一個突變來切換加載狀態,不如: 1. 類型為`REQUEST_SOMETHING`的突變,以切換加載狀態 2. 類型為`RECEIVE_SOMETHING_SUCCESS`的突變,用于處理成功回調 3. 類型為`RECEIVE_SOMETHING_ERROR`的突變,用于處理錯誤回調 4. 動作`fetchSomething`發出請求并在提到的情況下提交突變 1. 如果您的應用程序執行的不是`GET`請求,則可以使用以下示例: * `POST` : `createSomething` * `PUT` : `updateSomething` * `DELETE` : `deleteSomething` 結果,我們可以從該組件調度`fetchNamespace`操作,它將負責提交`REQUEST_NAMESPACE` , `RECEIVE_NAMESPACE_SUCCESS`和`RECEIVE_NAMESPACE_ERROR`突變. > 以前,我們是從`fetchNamespace`操作中調度操作,而不是提交突變,所以如果您在代碼庫的較早部分中找到了不同的模式,請不要感到困惑. 但是,無論何時您編寫新的 Vuex 商店,我們都鼓勵利用新模式 通過遵循這種模式,我們保證: 1. 所有應用程序都遵循相同的模式,從而使任何人都更容易維護代碼 2. 應用程序中的所有數據都遵循相同的生命周期模式 3. 單元測試更容易 #### Updating complex state[](#updating-complex-state "Permalink") 有時,尤其是當狀態復雜時,實際上很難遍歷該狀態以精確更新突變需要更新的內容. 理想情況下, `vuex`狀態應盡可能標準化/解耦,但這并非總是如此. 重要的是要記住,當在突變本身中選擇`portion of the mutated state`并對其進行突變時,代碼更易于閱讀和維護. 給定此狀態: ``` export default () => ({ items: [ { id: 1, name: 'my_issue', closed: false, }, { id: 2, name: 'another_issue', closed: false, } ] }); ``` 像這樣寫一個突變可能很誘人: ``` // Bad export default { [types.MARK_AS_CLOSED](state, item) { Object.assign(item, {closed: true}) } } ``` 盡管此方法有效,但它具有以下依賴性: * 正確的選擇`item`中的組件/動作. * `item`屬性已經在`closed`狀態下聲明. * 新的`confidential`財產將不會產生反應. * 他指出, `item`是通過引用`items` 這樣寫的突變更難維護,更容易出錯. 我們寧可這樣寫一個變異: ``` // Good export default { [types.MARK_AS_CLOSED](state, itemId) { const item = state.items.find(i => i.id == itemId); Vue.set(item, 'closed', true) state.items.splice(index, 1, item) } } ``` 這種方法更好,因為: * 它選擇并更新突變中的狀態,這種狀態更易于維護. * 它沒有外部依賴性,如果傳遞了正確的`itemId`則狀態將正確更新. * 它沒有反應性警告,因為我們生成了一個新`item`以避免耦合到初始狀態. 這樣寫的變異更容易維護. 另外,我們避免了由于反應系統的限制而導致的錯誤. ### `getters.js`[](#gettersjs "Permalink") 有時我們可能需要根據存儲狀態獲取派生狀態,例如針對特定道具進行過濾. 使用 getter 還將由于依賴關系而緩存結果,這取決于[計算的 props 的工作方式.](https://vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods)這可以通過`getters`來完成: ``` // get all the users with pets export const getUsersWithPets = (state, getters) => { return state.users.filter(user => user.pet !== undefined); }; ``` 要從組件訪問吸氣劑,請使用`mapGetters`幫助器: ``` import { mapGetters } from 'vuex'; { computed: { ...mapGetters([ 'getUsersWithPets', ]), }, }; ``` ### `mutation_types.js`[](#mutation_typesjs "Permalink") 來自[vuex 突變文檔](https://vuex.vuejs.org/guide/mutations.html) :>在各種 Flux 實現中,將常數用于突變類型是一種常見的模式. 這使代碼可以利用像 linters 這樣的工具,并將所有常量放在一個文件中,使您的協作者可以快速了解整個應用程序中可能發生的變異. ``` export const ADD_USER = 'ADD_USER'; ``` ### Initializing a store’s state[](#initializing-a-stores-state "Permalink") Vuex 存儲通常需要一些初始狀態才能使用其`action` . 通常,這些數據包括 API 端點,文檔 URL 或 ID 之類的數據. 要設置此初始狀態,請在安裝 Vue 組件時將其作為參數傳遞給商店的創建函數: ``` // in the Vue app's initialization script (e.g. mount_show.js) import Vue from 'vue'; import Vuex from 'vuex'; import { createStore } from './stores'; import AwesomeVueApp from './components/awesome_vue_app.vue' Vue.use(Vuex); export default () => { const el = document.getElementById('js-awesome-vue-app'); return new Vue({ el, store: createStore(el.dataset), render: h => h(AwesomeVueApp) }); }; ``` 然后,存儲功能可以將此數據傳遞給州的創建功能: ``` // in store/index.js import * as actions from './actions'; import mutations from './mutations'; import createState from './state'; export default initialState => ({ actions, mutations, state: createState(initialState), }); ``` 狀態函數可以接受此初始數據作為參數并將其烘焙到返回的`state`對象中: ``` // in store/state.js export default ({ projectId, documentationPath, anOptionalProperty = true }) => ({ projectId, documentationPath, anOptionalProperty, // other state properties here }); ``` #### Why not just …spread the initial state?[](#why-not-just-spread-the-initial-state "Permalink") 精明的讀者將從上面的示例中看到切出幾行代碼的機會: ``` // Don't do this! export default initialState => ({ ...initialState, // other state properties here }); ``` 我們已經做出有意識的決定,避免使用這種模式,以幫助我們的前端代碼庫實現可發現性和可搜索性. 在[此討論中](https://gitlab.com/gitlab-org/frontend/rfcs/-/issues/56#note_302514865)描述了[這樣做的原因](https://gitlab.com/gitlab-org/frontend/rfcs/-/issues/56#note_302514865) : > 考慮在存儲狀態中使用了`someStateKey` . 如果僅由`el.dataset`提供,則*可能*無法直接對其進行 grep. 相反,您必須 grep 以獲得`some_state_key` ,因為它可能來自 rails 模板. 反之亦然:如果您正在查看 Rails 模板,您可能想知道是什么使用了`some_state_key` ,但是您*必須* grep 為`someStateKey` ### Communicating with the Store[](#communicating-with-the-store "Permalink") ``` <script> import { mapActions, mapState, mapGetters } from 'vuex'; export default { computed: { ...mapGetters([ 'getUsersWithPets' ]), ...mapState([ 'isLoading', 'users', 'error', ]), }, methods: { ...mapActions([ 'fetchUsers', 'addUser', ]), onClickAddUser(data) { this.addUser(data); } }, created() { this.fetchUsers() } } </script> <template> <ul> <li v-if="isLoading"> Loading... </li> <li v-else-if="error"> {{ error }} </li> <template v-else> <li v-for="user in users" :key="user.id" > {{ user }} </li> </template> </ul> </template> ``` ### Vuex Gotchas[](#vuex-gotchas "Permalink") 1. 不要直接調用突變. 始終使用動作進行突變. 這樣做將在整個應用程序中保持一致性. 從 Vuex 文檔: > Why don’t we just call store.commit(‘action’) directly? Well, remember that mutations must be synchronous? Actions aren’t. We can perform asynchronous operations inside an action. ``` // component.vue // bad created() { this.$store.commit('mutation'); } // good created() { this.$store.dispatch('action'); } ``` 2. 使用變異類型而不是對字符串進行硬編碼. 這將減少出錯的可能性. 3. 在實例化商店的用途之后的所有組件中,都可以訪問 State. ### Testing Vuex[](#testing-vuex "Permalink") #### Testing Vuex concerns[](#testing-vuex-concerns "Permalink") 有關測試操作,獲取器和突變的信息,請參考[vuex 文檔](https://vuex.vuejs.org/guide/testing.html) . #### Testing components that need a store[](#testing-components-that-need-a-store "Permalink") 較小的組件可能會使用`store`屬性來訪問數據. 為了編寫這些組件的單元測試,我們需要包括商店并提供正確的狀態: ``` //component_spec.js import Vue from 'vue'; import Vuex from 'vuex'; import { mount, createLocalVue } from '@vue/test-utils'; import { createStore } from './store'; import Component from './component.vue' const localVue = createLocalVue(); localVue.use(Vuex); describe('component', () => { let store; let wrapper; const createComponent = () => { store = createStore(); wrapper = mount(Component, { localVue, store, }); }; beforeEach(() => { createComponent(); }); afterEach(() => { wrapper.destroy(); wrapper = null; }); it('should show a user', async () => { const user = { name: 'Foo', age: '30', }; // populate the store await store.dispatch('addUser', user); expect(wrapper.text()).toContain(user.name); }); }); ``` ### Two way data binding[](#two-way-data-binding "Permalink") 在 Vuex 中存儲表單數據時,有時需要更新存儲的值. 絕對不應直接更改存儲,而應使用操作. 為了在我們的代碼中仍然使用`v-model` ,我們需要以這種形式創建計算屬性: ``` export default { computed: { someValue: { get() { return this.$store.state.someValue; }, set(value) { this.$store.dispatch("setSomeValue", value); } } } }; ``` 另一種方法是使用`mapState`和`mapActions` : ``` export default { computed: { ...mapState(['someValue']), localSomeValue: { get() { return this.someValue; }, set(value) { this.setSomeValue(value) } } }, methods: { ...mapActions(['setSomeValue']) } }; ``` 添加其中一些屬性變得很麻煩,并使代碼重復性更高,并需要編寫更多的測試. 為了簡化此操作, `~/vuex_shared/bindings.js`有一個幫助器. 可以像這樣使用助手: ``` // this store is non-functional and only used to give context to the example export default { state: { baz: '', bar: '', foo: '' }, actions: { updateBar() {...} updateAll() {...} }, getters: { getFoo() {...} } } ``` ``` import { mapComputed } from '~/vuex_shared/bindings' export default { computed: { /** * @param {(string[]|Object[])} list - list of string matching state keys or list objects * @param {string} list[].key - the key matching the key present in the vuex state * @param {string} list[].getter - the name of the getter, leave it empty to not use a getter * @param {string} list[].updateFn - the name of the action, leave it empty to use the default action * @param {string} defaultUpdateFn - the default function to dispatch * @param {string} root - optional key of the state where to search fo they keys described in list * @returns {Object} a dictionary with all the computed properties generated */ ...mapComputed( [ 'baz', { key: 'bar', updateFn: 'updateBar' } { key: 'foo', getter: 'getFoo' }, ], 'updateAll', ), } } ``` 然后, `mapComputed`將生成適當的計算屬性,這些屬性從存儲中獲取數據并在更新時調度正確的操作.
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看