@TuMko

Возможно ли выполнить рефакторинг кода в приложении Vue 3?

Создаю приложение на Vue 3. И столкнулся с тем, что приходится создавать множество (10-15 шт.) одинаковых компонентов. Один такой компонент добавляет блок с инпутом для добавления на БД (mongo db) и списком всех значений, полученных из БД(mongo db), с возможностью удаления. Я понимаю, что создавать так много одинаковых компонентов не рационально и хотел бы улучшить свой код. Подскажите, возможно ли в моем случае создать универсальный компонент и каким образом?

Собственно, сам компонент, SettingscertQualifyingRanks.vue:
spoiler
<template>
  <div class="accordion-body">
    <div class="mb-3" v-if="certQualifyingRanks">
      <select
        class="form-select"
        size="4"
        multiple
        aria-label="multiple select example"
        v-model="selectedQualifyingRanks"
      >
        <option v-if="certQualifyingRanks.length === 0" disabled
          >Значений нет, добавьте новое</option
        >
        <option v-else disabled>Выберите значение</option>
        <option
          v-for="certQR in certQualifyingRanks"
          :key="certQR.id"
          :value="certQR._id"
          >{{ certQR.value }}
        </option>
      </select>

      <button
        class="btn btn-sm btn-outline-danger mt-2"
        type="button"
        @click="removeQualifyingRanks(selectedQualifyingRanks[0])"
      >
        Удалить
      </button>
    </div>
    <div class="input-group">
      <input
        id="qualifyRankInput"
        type="text"
        :class="['form-control', { 'is-invalid': qError }]"
        placeholder="Квалификационный разряд"
        aria-label="Квалификационный разряд"
        aria-describedby="button-addon2"
        v-model="qualifyingRank"
        @blur="qBlur"
        @change="qChange"
      />
      <button
        class="btn btn-outline-secondary"
        type="button"
        id="button-addon2"
        @click="onSubmitQualifyingRank"
      >
        Добавить
      </button>
    </div>
    <div class="form-text text-danger" v-if="qError">
      {{ qError }}
    </div>
  </div>
</template>

<script>
import { ref, computed, onMounted } from "vue";
import { useStore } from "vuex";
import { useField, useForm } from "vee-validate";
import * as yup from "yup";

export default {
  setup() {
    //подключаем store
    const store = useStore();
    //выбранное значение из select
    const selectedQualifyingRanks = ref([]);
    //
    const { isSubmitting, handleSubmit, resetForm } = useForm();

    const {
      value: qualifyingRank,
      errorMessage: qError,
      handleBlur: qBlur,
      handleChange: qChange,
    } = useField(
      "qualifyingRank",
      yup
        .string()
        .trim()
        .required("Введите квалификационный разряд")
    );

    //загрузка значений:
    onMounted(async () => {
      //выполнение в store экшена load
      await store.dispatch("certQualifyingRank/load");
    });

    // возвращаем значение certQualifyingRanks из store (берем список значений из store)
    const certQualifyingRanks = computed(
      () => store.getters["certQualifyingRank/certQualifyingRanks"]
    );

    //добавить новое значение:
    const submitQualifyingRank = async (values) => {
      // вызываем метод create для создания записи в БД
      await store.dispatch("certQualifyingRank/create", values);
      //обновить список:
      await store.dispatch("certQualifyingRank/load");

      //очистка поля ввода
      resetForm();
    };

    const onSubmitQualifyingRank = handleSubmit(submitQualifyingRank);

    //удалить значение:
    const removeQualifyingRanks = async (id) => {
      await store.dispatch("certQualifyingRank/remove", id);
      //обновить список:
      await store.dispatch("certQualifyingRank/load");
      //очистить список значений на удаление:
      selectedQualifyingRanks.value = [];
    };

    return {
      certQualifyingRanks,
      removeQualifyingRanks,
      selectedQualifyingRanks,

      isSubmitting,
      onSubmitQualifyingRank,
      qualifyingRank,
      qError,
      qBlur,
      qChange,
      resetForm,
    };
  },
};
</script>


Модуль из store/ cert-qualifying-rank.module.js :
spoiler
import axios from "../../axios/request";
import store from "../index";

export default {
  namespaced: true,
  state() {
    return {
      certQualifyingRanks: [],
    };
  },
  mutations: {
    //обновление в хранилище setCertQualifyingRanks[]
    setCertQualifyingRanks(state, certQualifyingRanks) {
      state.certQualifyingRanks = certQualifyingRanks;
    },
    //добавление новых значений в хранилище setCertQualifyingRanks[]
    addCertQualifyingRank(state, certQualifyingRank) {
      state.certQualifyingRanks.push(certQualifyingRank);
    },
  },
  actions: {
    async create({ commit, dispatch }, payload) {
      try {
        //получаем токен из store
        const token = store.getters["auth/token"];

        const dataload = {
          value: payload.qualifyingRank,
        };

        const headers = {
          "Content-Type": "application/json",
          Authorization: `Bearer ${token}`,
        };

        const data = await axios.post(
          "api/certificate-qualifying-rank/create",
          dataload,
          {
            headers: headers,
          }
        );

        dispatch(
          "setMessage",
          {
            value: "Новое значение успешно добавлено ",
            type: "primary",
          },
          { root: true }
        );
      } catch (e) {
        dispatch(
          "setMessage",
          {
            value: e + "\n Вероятно такое значение уже добавлено",
            type: "danger",
          },
          { root: true }
        );

        throw e;
      }
    },
    async load({ commit, dispatch }) {
      try {
        //получаем токен из store
        const token = store.getters["auth/token"];

        const headers = {
          "Content-Type": "application/json",
          Authorization: `Bearer ${token}`,
        };

        //загрузка с БД сервера
        const { data } = await axios.get("api/certificate-qualifying-rank/", {
          headers: headers,
        });
       
        const certQualifyingRanks = Object.keys(data).map((id) => ({
          ...data[id],
          id,
        }));

        //вызываем mutation setCertQualifyingRanks
        commit("setCertQualifyingRanks", certQualifyingRanks);
      } catch (e) {
        dispatch(
          "setMessage",
          {
            value: e,
            type: "danger",
          },
          { root: true }
        );

        throw e;
      }
    },

    async remove({ commit, dispatch }, id) {
      try {
        //получаем токен из store
        const token = store.getters["auth/token"];

        const headers = {
          "Content-Type": "application/json",
          Authorization: `Bearer ${token}`,
        };

        const { data } = await axios.delete(
          `api/certificate-qualifying-rank/${id}`,
          {
            headers: headers,
          }
        );
        
        dispatch(
          "setMessage",
          {
            value: data.message || "Значение успешно удалено",
            type: "primary",
          },
          { root: true }
        );
      } catch (e) {
        dispatch(
          "setMessage",
          {
            value: e.message,
            type: "danger",
          },
          { root: true }
        );
      }
    },
  },
  getters: {
    certQualifyingRanks(state) {
      return state.certQualifyingRanks;
    },
  },
};
  • Вопрос задан
  • 175 просмотров
Решения вопроса 1
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Для начала стоит вынести в отдельный плагин REST-запросы, чтобы каждый раз не писать работу с заголовками. Сделать отдельный класс с методами get/post/put/path/delete и, заодно, закрыть в нём всю работу с токенами и авторизацией.
Затем, стоит посмотреть, так ли необходимо здесь использование store. Если данные используются только в одном компоненте, то, IMHO, от store стоит отказаться и хранить данные в самом компоненте.
После этого у вас останутся компоненты, различающиеся, скорее всего, только строкой в плейсхолдере, текстом ошибки и начальной частью пути в url запросов. Всё это можно передать из родительского компонента через параметры.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы