搜尋

首頁  >  問答  >  主體

Pinia 中的繼承/共享操作和吸氣劑

我有幾個 Pinia 商店,它們應該共享一組操作和 getter,但我不太確定如何有效地實現這一點。

我正在建立一個應用程序,讓用戶可以管理多種不同的媒體(書籍、電影、電視節目等)。我目前考慮的方式是為每種媒體類型建立一個商店,例如BookStore、MovieStore 等。這些不同商店之間的許多 getter 和操作(例如 countdeleteOne)完全相同。

如何在這裡實作 DRY? Pinia 文件中的範例主要集中在其他商店內重複使用操作和 getter,但我認為這並不能完全解決我直接繼承一組 getter 和 setter 的用例。

我在這裡嘗試的繼承方法是反模式嗎?

P粉662614213P粉662614213336 天前503

全部回覆(2)我來回復

  • P粉420958692

    P粉4209586922023-12-23 12:54:52

    如果您想讓某些功能在並非所有商店之間共享,您可以使用可組合方式。

    您可以建立一個單獨的可組合函數並將商店實例的一部分傳遞給其中。

    我在 codesandbox 上做了一個例子為你。

    這裡是codesandbox的簡短範例:

    common.ts

    #
    import { computed, Ref, ref } from "vue";
    
    export function useCommon(initValue: number) {
        const _value = ref<number>(initValue);
    
        function increment() {
            _value.value++;
        }
    
        function someProcessing() {
            // ... some code here
        }
    
        return {
            counter,
    
            increment,
            someProcessing,
        };
    }

    然後在任何商店中您都可以像這樣使用它:

    fooStore.ts

    export const useFooStore = defineStore('foo', () => {
        const state = ref<string>('foo');
    
        const { counter, increment, someProcessing } = useCounter(0);
    
        return {
            state,
    
            counter,
            increment,
            someProcessing,
        }
    }

    透過這種方式,您可以在任何儲存或任何元件中組合任何函數、物件等。

    回覆
    0
  • P粉449281068

    P粉4492810682023-12-23 00:43:42

    這可以使用外掛程式來實作 docs

    範例電影:

    #您有多個商店,每個州都使用共享命名方案:

    • 專案:單一實體專案(單一電影詳細資訊)
    • collection:項目集合(所有電影的集合)

    每個商店都會有相同的 CRUD 操作,只是 URL 發生變化

    建立外掛:

    #
    function BaseStorePlugin () {
        return {
            collection: [],
            item: {},
            getCollection: function (url) {
                api.get(url)
                    .then((response) => {
                        this.collection = response.data;
                    })
                    .catch((error) => {
                        this.handleError(error);
                    });
            },
            getItem: function (url) {
                api.get(url)
                    .then((response) => {
                        this.item = response.data;
                    })
                    .catch((error) => {
                        this.handleError(error);
                    });
            },
            handleError: function (error) {
                window.alert(error);
            },
        };
    }

    提供 Pinia 外掛:

    const pinia = createPinia();
    
    pinia.use(BaseStorePlugin);

    範例 movieStore.js(使用共用操作和狀態)

    import { defineStore } from 'pinia';
    import { api } from 'src/boot/axios';
    
    export const useMovieStore = defineStore({
        id: 'movie',
        state: () => ({
            movieSpecificStateObject: {},
        }),
        actions: {
            movieSpecificAction (url) {
                console.log(this.item);
                api.get(url)
                    .then((response) => {
                        // handle response
                    })
                    .catch((error) => {
                        this.handleError(error);
                    });
            },
        },
    });

    元件中的使用範例

    #
    <template>
        <div
            v-for="movie in movieStore.collection"
            :key="movie.id"
        >
            <div>
                {{ movie.name }}
            </div>
        </div>
    </template>
    
    <script setup>
    import { onMounted } from 'vue';
    import { useMovieStore } from 'src/stores/movieStore.js';
    const movieStore = useMovieStore();
    
    onMounted(() => {
        movieStore.readCollection('http://url.com/movies');
    });
    </script>

    編輯:1

    #如果您將上下文傳遞到外掛程式中,您就可以存取商店和傳遞到其中的選項,從中您可以檢查商店 ID,並且僅返回特定商店,如下所示

    function BaseStorePlugin (context) {
      const allowedStores = ['movie', 'album'];
    
      if (allowedStores.includes(context.store.$id)) {
        return {
          collection: [],
          getCollection: function () {
            const fakeCollection = Array.from({length: 10}, () => Math.floor(Math.random() * 40));
            fakeCollection.forEach((item) => {
              this.collection.push({
                id: item,
                name: `name${item}`
              });
            });
          },
        };
      };
    }

    我使用 3 個商店創建了一個非常基本的範例,上面的檢查可在 codesandbox 這裡< /a>

    回覆
    0
  • 取消回覆