programing

Vuex/Pinia 스토어에서의 관계를 어떻게 처리하고 동기화 상태를 유지합니까?

shortcode 2022. 7. 27. 00:02
반응형

Vuex/Pinia 스토어에서의 관계를 어떻게 처리하고 동기화 상태를 유지합니까?

컴포지션 API와 함께 Vue3를 사용하고 있습니다.이 예에서는 Pinia를 사용하지만 이는 Vuex에도 적용됩니다.

유형 엔티티 B의 엔티티 A의 지주 엔티티를 관리해야 한다고 상상해 보십시오.이 예에서는 라벨을 여러 개 보유한 단일 ToDO를 사용합니다.

레이블의 표본 저장소

export type Label = {
  title: string; // "unique"
};

export const useLabelsStore = defineStore("labels", () => {
  const labels = ref<Label[]>([]);

  function addLabel(title: string): void {
    if (!labels.value.some((label) => label.title === title)) {
      labels.value.push({ title });
    }
  }

  function deleteLabel(title: string): void {
    labels.value = labels.value.filter((label) => label.title !== title);
  }

  return { labels, addLabel, deleteLabel };
});

그리고 할 일을 위해서

export type Todo = {
  title: string; // "unique"
  labels: Label[];
};

export const useTodosStore = defineStore("todos", () => {
  const todos = ref<Todo[]>([{ title: "foo", labels: [] }]);

  function applyLabelToTodo(todoTitle: string, label: Label) {
    const todo = todos.value.find((todo) => todo.title === todoTitle);

    if (
      todo &&
      !todo.labels.some((todoLabel) => todoLabel.title === label.title)
    ) {
      todo.labels.push(label);
    }
  }

  return { todos, applyLabelToTodo };
});

ToDOS, 라벨 작성 및 ToDOS에 라벨 적용 할 수 있습니다.그러나 Todo에 라벨을 붙이고 삭제한 후에도 Todo는 여전히 그것을 유지하고 있기 때문에 코드에는 아직 동기 메커니즘이 없기 때문에 Todos 스토어는 "비활성"/"구식"이 아닙니다.

테스트용 App.vue 파일이 표시됩니다.

<template>
  <div>
    <div>Labels: {{ labelsStore.labels }}</div>

    <br />

    <div v-for="todo in todosStore.todos" :key="todo.title">
      <div>Todo: {{ todo.title }}</div>
      <div>Applied labels: {{ todo.labels }}</div>
    </div>

    <br />

    <button @click="addLabel">Add new label</button>

    <br />
    <br />

    <select v-model="selectedLabelTitle">
      <option
        v-for="label in labelsStore.labels"
        :value="label.title"
        :key="label.title"
      >
        {{ label.title }}
      </option>
    </select>

    <button @click="labelsStore.deleteLabel(selectedLabelTitle)">
      Delete label "{{ selectedLabelTitle }}"
    </button>
    <button @click="applyLabelToTodo">
      Apply label "{{ selectedLabelTitle }}" to todo "{{
        todosStore.todos[0].title
      }}"
    </button>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from "vue";

import { useTodosStore } from "./todosStore";
import { useLabelsStore } from "./labelsStore";

export default defineComponent({
  setup() {
    const todosStore = useTodosStore();
    const labelsStore = useLabelsStore();

    const selectedLabelTitle = ref<string>();

    function addLabel(): void {
      labelsStore.addLabel(`Label ${labelsStore.labels.length + 1}`);
    }

    function applyLabelToTodo(): void {
      const label = labelsStore.labels.find(
        (label) => label.title === selectedLabelTitle.value
      );

      if (label) {
        todosStore.applyLabelToTodo(todosStore.todos[0].title, label);
      }
    }

    return {
      todosStore,
      labelsStore,
      addLabel,
      selectedLabelTitle,
      applyLabelToTodo,
    };
  },
});
</script>
  • todos 저장소에 이미 할 일이 있습니다.
  • "Add new label"을 클릭합니다.
  • 선택 상자에서 선택합니다.
  • 작업관리에 해당 레이블 적용
  • 해당 라벨 삭제

이 작업관리에는 삭제된 라벨이 남아 있습니다.

스토어를 동기화하는 일반적인 방법은 무엇입니까?액션 서브스크라이브를 기반으로 하는 현재의 솔루션은 todos 스토어를 확장하는 것입니다.

export const useTodosStore = defineStore("todos", () => {
  // ...

  const labelsStore = useLabelsStore();

  labelsStore.$onAction((context) => {
    if (context.name === "deleteLabel") {
      context.after(() => {
        todos.value = todos.value.map((todo) => {
          todo.labels = todo.labels.filter(
            (label) => label.title !== context.args[0]
          );

          return todo;
        });
      });
    }
  });

  // ...
});

모든 행동에 귀를 기울여야 하나요, 아니면 더 나은 방법이 있나요?

스토어를 정의하고 Vue reactive API로 직접 정의할 수 있는 공장 기능은 일반적으로 필요하지 않은 고급 기능입니다.저장소는 일반적으로 Vuex API와 유사한 개체로 정의됩니다.

다른 값에서 파생될 것으로 예상되는 값은 Vue 계산값과 매우 유사하게 getter로 전송됩니다.computed는 Vue reactive API의 일부로 Pinia에서 내부적으로 사용됩니다).

예를 들어, 다른 스토어의 최신 라벨에 대해 ToDo 라벨을 필터링할 수 있습니다.

const todoStore = defineStore({
  state: () => ({ _todos: [] })
  getters: {
    todos() {
      const labelStore = useLabelStore();

      return this._todos
      .map((todo) => ({
        ...todo,
        labels: todo.labels.filter(label => labelStore.labels.includes(label))
      });
    }
  }
});

언급URL : https://stackoverflow.com/questions/69760682/how-to-deal-with-relations-in-vuex-pinia-stores-and-keep-them-in-sync

반응형