T
T
TuMko2021-11-14 21:31:48
JavaScript
TuMko, 2021-11-14 21:31:48

Is it possible to refactor code in a Vue 3 app?

I am creating an application on Vue 3. And I faced the fact that I have to create a lot (10-15 pieces) of the same components. One such component adds a block with an input to add to the database (mongo db) and a list of all values ​​received from the database (mongo db), with the possibility of deletion. I understand that creating so many identical components is not rational and would like to improve my code. Tell me, is it possible in my case to create a universal component and how?

Actually, the component itself, 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>


Module from 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;
    },
  },
};

Answer the question

In order to leave comments, you need to log in

1 answer(s)
R
Rsa97, 2021-11-15
@TuMko

For starters, it’s worth moving REST requests into a separate plugin so that you don’t have to write work with headers every time. Make a separate class with get/post/put/path/delete methods and, at the same time, close all work with tokens and authorization in it.
Next, it's worth looking at whether the use of store is necessary here. If the data is used only in one component, then, IMHO, store should be abandoned and data stored in the component itself.
After that, you will have components that most likely differ only in the string in the placeholder, the error text, and the initial part of the path in the request url. All this can be passed from the parent component through parameters.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question