स्केलेबिलिटी को ध्यान में रखते हुए फुल-स्टैक एप्लिकेशन बनाना डराने वाला हो सकता है, खासकर जब Vue और Vuex के नवीनतम संस्करण के साथ निर्माण किया जाता है, जिसमें पूर्ण टाइपस्क्रिप्ट समर्थन होता है। यह लेख अपने पाठकों को वह सब कुछ सिखाएगा जो उन्हें राज्य प्रबंधन से Vuex 4.0 के साथ स्केलेबल फुल-स्टैक एप्लिकेशन के निर्माण के बारे में जानने की जरूरत है, ताकि एक CRUD एप्लिकेशन की खोज करके API अनुरोधों और डेटाबेस इंटरैक्शन को संभाला जा सके जो अस्वास्थ्यकर पशुधन के लिए उपचार के नुस्खे का प्रबंधन करता है। बैकएंड को रेल के साथ बनाया जाएगा, जो फ्रंटएंड द्वारा एकीकरण के लिए बुनियादी सीआरयूडी एपीआई को उजागर करेगा।
अधिकांश कंपनियों ने एपीआई-आधारित विकास वास्तुकला को अपनाया क्योंकि यह फ्रंटएंड डेवलपमेंट टीम को विकास के लिए उपयुक्त फ्रंटएंड टूल चुनने के लिए अधिक लचीलापन देता है। हालांकि यह सबसे अच्छा विकल्प नहीं हो सकता है, यह एक विश्वसनीय विकल्प रहा है, और कई कंपनियों ने इस विकास वास्तुकला को अपनाया है क्योंकि यह टीम में अधिक लचीलापन जोड़ता है।
आवश्यकताएँ
इससे पहले कि हम शुरू करें, सुनिश्चित करें कि इस ट्यूटोरियल के साथ बने रहने के लिए आपके पास निम्नलिखित हैं:
- रेल V6.x
- Node.js V10.x
- रूबी ऑन रेल्स का पूर्व कार्यसाधक ज्ञान
- टाइपस्क्रिप्ट का पूर्व कार्यसाधक ज्ञान
- Vue.js का पूर्व कार्यसाधक ज्ञान
हम क्या बनाएंगे
इस ट्यूटोरियल में, हम एक पूर्ण-स्टैक सीआरयूडी एप्लिकेशन का निर्माण करेंगे जो अस्वस्थ पशुधन के लिए उपचार के नुस्खे का प्रबंधन करता है। उपयोगकर्ता पशुधन के लिए नुस्खे बनाने, अपडेट करने और हटाने में सक्षम होंगे। सीआरयूडी एपीआई को रेल का उपयोग करके बनाया जाएगा, सीआरयूडी एपीआई को फ्रंटएंड द्वारा एकीकरण के लिए उजागर किया जाएगा, जिसे वीयू 3 के साथ बनाया जाएगा। इनमें से प्रत्येक स्टैक स्वतंत्र अनुप्रयोगों के रूप में विभिन्न बंदरगाहों पर चलेंगे।
पूर्ण-स्टैक ऐप का मूल आर्किटेक्चर
हमारा फुल-स्टैक एप्लिकेशन क्लाइंट और सर्वर एप्लिकेशन दोनों से स्वतंत्र रूप से चल रहा है, क्लाइंट एप्लिकेशन के प्रत्येक घटक के साथ सर्वर एप्लिकेशन द्वारा जारी किए गए CRUD API के साथ Vuex के माध्यम से एप्लिकेशन स्टेट के उचित प्रबंधन के लिए इंटरैक्ट करता है। बैकएंड एप्लिकेशन सीआरयूडी एपीआई को फ्रंटएंड एप्लिकेशन में उजागर करते हुए सभी नुस्खे डेटा को स्क्लाइट 3 डेटाबेस में संग्रहीत करता है।
बैकएंड सेवा सेटअप
अपनी पसंद के फ़ोल्डर में, निम्न आदेश चलाकर एक रेल ऐप बनाएं:
rails new vet_clinic_api --api
यह रेल को इस परियोजना को एपीआई के रूप में बनाने के लिए कहेगा, जिससे सभी फ्रंटएंड निर्भरता (फाइलें देखें) को हटा दिया जाएगा।
डेटाबेस कॉन्फ़िगरेशन
हम स्क्लाइट 3 का उपयोग करेंगे, जो कि रेल अनुप्रयोगों के लिए डिफ़ॉल्ट डेटाबेस है।
rails g scaffold prescriptions vet_prescription:text prescribed_by:text disease:text livestock:text completed:boolean
उपरोक्त कमांड चलाकर, रेल हमारे माइग्रेशन, टेस्ट, मॉडल, कंट्रोलर, रूट के लिए एक प्रारंभिक संरचना तैयार करेगी:
rails db:migrate
यह कमांड हमारे टेबल को डेटाबेस में जोड़ देगा।
डेटाबेस को सीडिंग करना
आइए हमारे डेटाबेस को कुछ नुस्खे डेटा के साथ सीड करें। नीचे दिए गए कोड स्निपेट को db/migrate/seed.rb
में जोड़ें
//db/migrate/seed.rb
Prescription.destroy_all
Prescription.create!([{
vet_prescription:"Achyranthes aspera",
prescribed_by:"Dr Chucks",
disease:"Rabbies",
livestock:"goat",
completed:false
},
{
vet_prescription:"Achyranthes aspera",
prescribed_by:"Dr Rex",
disease:"Rabbies",
livestock:"Dog",
completed:false
},
{
vet_prescription:"ethnovet",
prescribed_by:"Dr Chucks",
disease:"Pox",
livestock:"Sheep",
completed:false
}])
p "Created #{Prescription.count} prescriptions"
यह फ़ाइल डेटाबेस को सीड करने के लिए प्रारंभिक डेटा संग्रहीत करेगी ताकि जब ऐप शुरू हो, तो हमारे पास कुछ मौजूदा नुस्खे डेटा हों।
db/migrate/seed.rb
में कोड निष्पादित करने के लिए निम्न कमांड चलाएँ , जो कुछ पूर्वनिर्धारित नुस्खे डेटा के साथ डेटाबेस को सीड करता है:
rails db:seed
इन कुछ आदेशों के साथ, हमने रेल के साथ एक कार्यात्मक सीआरयूडी एपीआई बनाया। कितना आसान था? (मुस्कान)
CORS कॉन्फ़िगरेशन
चूंकि हम अपने सीआरयूडी एपीआई को फ्रंटएंड में उजागर करेंगे, और फ्रंटएंड और बैकएंड सर्वर दोनों एक अलग पोर्ट पर चल रहे होंगे, हमें फ्रंटएंड के बीच डेटा शेयरिंग तक पहुंच प्रदान करने के लिए रेल बैकएंड पर एक सीओआरएस कॉन्फ़िगरेशन सेट करने की आवश्यकता है। बैकएंड।
Gemfile
का पता लगाएँ प्रोजेक्ट रूट में और कोड की निम्न पंक्ति को अनकम्मेंट करें:
# gem 'rack-cors'
निम्न कोड को config/environments/initializers/cors.rb
में जोड़ें :
//config/environments/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
उपरोक्त स्निपेट किसी भी पोर्ट पर चल रहे फ्रंटएंड ऐप्स से रेल सीआरयूडी एपीआई को एक्सेस करने की अनुमति देता है।
रेल सर्वर शुरू करने के लिए निम्न कमांड चलाएँ:
rails s
localhost:3000/prescriptions
पर नेविगेट करें सभी नुस्खे के लिए JSON प्रतिक्रिया प्राप्त करने के लिए।
रेल का उपयोग करने पर विचार करें यदि आप उन ग्राहकों के साथ काम कर रहे हैं जो अपनी परियोजनाओं के वर्कफ़्लो को बार-बार बदलते हैं। रेल के साथ, कुछ कमांड और कोड की पंक्तियों के साथ सुविधाओं को लागू करना आसान है। हालांकि यह मेरी निजी राय है।
पेश है Vue
Vue एक प्रगतिशील ढांचा है यूजर इंटरफेस बनाने के लिए। वेब अनुप्रयोगों के लिए महत्वपूर्ण प्रदर्शन अनुकूलन प्रदान करने के लिए Vue ने वर्चुअल DOM, रेंडर फ़ंक्शंस और सर्वर-साइड रेंडरिंग क्षमताओं जैसी अवधारणाओं का परिचय दिया।
Vue 3 डेवलपर्स के लिए बहुत सी नई सुविधाओं और परिवर्तनों के साथ आता है। इन सुविधाओं को ढांचे की समग्र स्थिरता, साथ ही इसकी गति और रखरखाव में सुधार करने के लिए डिज़ाइन किया गया है।
हम कंपोजीशन एपीआई का उपयोग करेंगे, जो Vue 3 की सबसे प्रत्याशित विशेषताओं में से एक है। यह Vue घटकों को बनाने का एक नया तरीका है, कोड लिखने के लिए एक अधिक संगठित और कुशल दृष्टिकोण और पूर्ण टाइपस्क्रिप्ट टाइप-चेकिंग समर्थन के साथ।पी>
पेश है Vuex
Vuex, Vue टीम द्वारा बनाई गई एक राज्य प्रबंधन लाइब्रेरी है, और यह Redux के समान फ्लक्स आर्किटेक्चर पर आधारित है। इसे विशेष रूप से Vue . के लिए डिज़ाइन किया गया है और आपके स्टोर के बेहतर संगठन की अनुमति देता है। यदि आपके Vue एप्लिकेशन की स्थिति बढ़ने के साथ-साथ अधिक जटिल होती जाती है, तो Vuex महत्वपूर्ण हो जाएगा। Vuex की नवीनतम स्थिर रिलीज़, v4.0.0, Vue 3 में पेश किए गए कंपोज़िशन एपीआई का समर्थन करती है, साथ ही टाइपस्क्रिप्ट के लिए एक अधिक मजबूत अनुमान।
फ़्रंटएंड एप्लिकेशन सेट करना
फ्रंटएंड को Vue 3 और टाइपस्क्रिप्ट के साथ सेटअप किया जाएगा, जबकि Vuex का उपयोग एप्लिकेशन स्टेट मैनेजमेंट के लिए किया जाएगा।
आइए टाइपस्क्रिप्ट समर्थन के साथ Vue 3 ऐप बनाने के लिए Vue-CLI टूल का उपयोग करके शुरुआत करें।
Vue-CLI टूल को विश्व स्तर पर निम्न कमांड के साथ इंस्टॉल करें:
npm install --global @vue/cli
नीचे दिए गए कमांड के साथ टाइपस्क्रिप्ट और Vuex सपोर्ट के साथ एक नया Vue 3 ऐप बनाएं:
vue create vet_clinic_frontend
मैन्युअल रूप से चुनें सुविधा विकल्प चुनें और निम्नलिखित विकल्पों का चयन करने के लिए स्पेस कुंजी दबाएं:
- Vue संस्करण चुनें
- बेबेल
- टाइपस्क्रिप्ट
- लिंटर / फ़ॉर्मेटर
इसके बाद, प्रोजेक्ट के संस्करण के रूप में Vue 3.x (पूर्वावलोकन) चुनें।
- क्लास-शैली घटक सिंटैक्स का उपयोग करने के लिए हाँ दर्ज करें।
- टाइपस्क्रिप्ट के साथ बैबेल का उपयोग करने के लिए हाँ दर्ज करें।
- अपनी पसंद का कोई भी लिंटर चुनें।
Vue 3 ऐप के सफलतापूर्वक जनरेट होने के बाद, हमारे पास Vuex (V4.x) और पूर्ण टाइपस्क्रिप्ट समर्थन के साथ Vue 3 प्रोजेक्ट सेटअप होगा।
हम टाइपस्क्रिप्ट का उपयोग करके एप्लिकेशन में टाइप सेफ्टी जोड़ेंगे। डेवलपमेंट सर्वर शुरू करने के लिए, अपने टर्मिनल में नीचे कमांड चलाएँ और https://localhost:8080
पर जाएँ। ब्राउज़र में अपने प्रोजेक्ट का पूर्वावलोकन करने के लिए।
हम अपने एप्लिकेशन को स्टाइल करने के लिए Bulma CSS फ्रेमवर्क का उपयोग करेंगे। Bulma CSS को इंस्टाल करने के लिए निम्न कमांड चलाएँ:
npm install bulma
Bulma CSS आयात करने के लिए, निम्न कोड को App.vue
में जोड़ें :
//App.vue
<style lang="scss">
@import "~bulma/css/bulma.css";
</style>
एप्लिकेशन स्टोर सेट करना
एप्लिकेशन स्टोर को Vuex के साथ सेटअप किया जाएगा। स्टोर में परिवर्तन करने के लिए, घटक से क्रियाएं भेजी जाएंगी, जो म्यूटेशन को ट्रिगर करती है, जिससे स्टोर अपडेट होता है।
एप्लिकेशन स्टोर स्थापित करने के लिए निम्नलिखित कदम उठाएं:
- राज्य की वस्तुएं बनाएं।
- हमारे एप्लिकेशन में होने वाले म्यूटेशन को सेट करें।
- ऐसी कार्रवाइयां बनाएं जो इन बाद के म्यूटेशनों के लिए प्रतिबद्ध होंगी।
- राज्य डेटा की सीधे गणना करने के लिए घटकों के लिए गेटर्स बनाएं।
राज्य
एक राज्य एक स्टोर ऑब्जेक्ट है जिसमें एप्लिकेशन-स्तरीय डेटा होता है जिसे सभी घटकों द्वारा एक्सेस करने की आवश्यकता होती है।
एक state.ts
बनाएं निम्न कोड स्निपेट के साथ स्टोर निर्देशिका में फ़ाइल करें:
//src/store/state.ts
export type Prescription = {
id: number;
vet_prescription: string;
prescribed_by: string;
disease: string;
livestock: string;
completed: boolean;
editing: boolean;
};
export type Data = {
vet_prescription: string;
prescribed_by: string;
disease: string;
livestock: string;
};
export type State = {
loading: boolean;
prescriptions: Prescription[];
data: Data | null;
showCreateModal: boolean;
showEditModal: boolean;
showPrescriptionModal: boolean;
editModalPrescriptionId: number | undefined;
showPrescriptionId: number | undefined;
};
export const state: State = {
loading: false,
prescriptions: [],
data: null,
showCreateModal: false,
showEditModal: false,
showPrescriptionModal: false,
editModalPrescriptionId: undefined,
showPrescriptionId: undefined,
};
यहां, हम Prescription
. में कुछ प्रकार की सुरक्षा जोड़ते हैं और Data
. हम प्रकार भी निर्यात करते हैं क्योंकि उनका उपयोग गेटर्स, म्यूटेशन और क्रियाओं की परिभाषाओं में किया जाएगा। अंत में, हम राज्य प्रकार को राज्य में डालते हैं।
म्यूटेशन
उत्परिवर्तन ऐसे तरीके हैं जो ट्रिगर होने पर स्टोर को संशोधित करते हैं। वे राज्य को पहले तर्क के रूप में प्राप्त करते हैं और दूसरे के रूप में पेलोड, अंततः पेलोड के साथ एप्लिकेशन स्थिति को संशोधित करते हैं। म्यूटेशन बनाने के लिए, Vuex डॉक्स म्यूटेशन प्रकारों के लिए स्थिरांक का उपयोग करने की सलाह देते हैं।
एक mutations.ts
बनाएं निम्न कोड स्निपेट के साथ स्टोर निर्देशिका में फ़ाइल करें:
//src/store/mutations.ts
import { MutationTree } from "vuex";
import { State, Prescription, Data } from "./state";
export enum MutationType {
CreatePrescription = "CREATE_PRESCRIPTION",
SetPrescriptions = "SET_PRESCRIPTIONS",
CompletePrescription = "COMPLETE_PRESCRIPTION",
RemovePrescription = "REMOVE_PRESCRIPTION",
EditPrescription = "EDIT_PRESCRIPTION",
UpdatePrescription = `UPDATE_PRESCRIPTION`,
SetLoading = "SET_LOADING",
SetCreateModal = "SET_CREATE_MODAL",
SetEditModal = "SET_EDIT_MODAL",
SetPrescriptionModal = "SET_PRESCRIPTION_MODAL",
}
उपरोक्त स्निपेट हमारे ऐप में म्यूटेशन के सभी संभावित नामों को रखने के लिए एनम प्रतीक का उपयोग करता है।
इसके बाद, हम प्रत्येक MutationType के लिए एक अनुबंध (प्रकार) की घोषणा करेंगे, जो इस प्रकार है:
//src/store/mutation.ts
export type Mutations = {
[MutationType.CreatePrescription](state: State, prescription: Data): void;
[MutationType.SetPrescriptions](state: State, prescription: Prescription[]): void;
[MutationType.CompletePrescription](state: State, prescription: Partial<Prescription> & { id: number }): void;
[MutationType.RemovePrescription](state: State, prescription: Partial<Prescription> & { id: number }): void;
[MutationType.EditPrescription](state: State, prescription: Partial<Prescription> & { id: number }): void;
[MutationType.UpdatePrescription](state: State, prescription: Partial<Prescription> & { id: number }): void;
[MutationType.SetLoading](state: State, value: boolean): void;
[MutationType.SetCreateModal](state: State, value: boolean): void;
[MutationType.SetEditModal](state: State, value: { showModal: boolean; prescriptionId: number | undefined }): void;
[MutationType.SetPrescriptionModal](state: State, value: { showModal: boolean; prescriptionId: number | undefined }): void;
};
फिर, हम प्रत्येक MutationType
. के लिए घोषित अनुबंधों को लागू करेंगे , इस प्रकार:
//src/store/mutation.ts
export const mutations: MutationTree<State> & Mutations = {
[MutationType.CreatePrescription](state, prescription) {
state.data == prescription;
},
[MutationType.SetPrescriptions](state, prescriptions) {
state.prescriptions = prescriptions;
},
[MutationType.CompletePrescription](state, newPrescription) {
const prescription = state.prescriptions.findIndex((prescription) => prescription.id === newPrescription.id);
if (prescription === -1) return;
state.prescriptions[prescription] = { ...state.prescriptions[prescription], ...newPrescription };
},
[MutationType.RemovePrescription](state, Prescription) {
const prescription = state.prescriptions.findIndex((prescription) => prescription.id === Prescription.id);
if (prescription === -1) return;
//If prescription exist in the state, remove it
state.prescriptions.splice(prescription, 1);
},
[MutationType.EditPrescription](state, Prescription) {
const prescription = state.prescriptions.findIndex((prescription) => prescription.id === Prescription.id);
if (prescription === -1) return;
//If prescription exist in the state, toggle the editing property
state.prescriptions[prescription] = { ...state.prescriptions[prescription], editing: !state.prescriptions[prescription].editing };
console.log("prescription", state.prescriptions[prescription]);
},
[MutationType.UpdatePrescription](state, Prescription) {
state.prescriptions = state.prescriptions.map((prescription) => {
if (prescription.id === Prescription.id) {
return { ...prescription, ...Prescription };
}
return prescription;
});
},
[MutationType.SetLoading](state, value) {
state.loading = value;
},
[MutationType.SetCreateModal](state, value) {
state.showCreateModal = value;
},
[MutationType.SetEditModal](state, value) {
state.showEditModal = value.showModal;
state.editModalPrescriptionId = value.prescriptionId;
},
[MutationType.SetPrescriptionModal](state, { showModal, prescriptionId }) {
state.showPrescriptionModal = showModal;
state.showPrescriptionId = prescriptionId;
},
};
MutationTree
Vuex पैकेज के साथ शिप किया गया एक सामान्य प्रकार है। हमने इसे उपरोक्त स्निपेट में एक प्रकार का उत्परिवर्तन वृक्ष घोषित करने के लिए उपयोग किया है। उत्परिवर्तन वृक्ष और उत्परिवर्तन यह सुनिश्चित करते हैं कि अनुबंध सही ढंग से कार्यान्वित किया गया है; अन्यथा, टाइपप्रति त्रुटि उत्पन्न करेगा।
कार्रवाइयां
क्रियाएँ वे विधियाँ हैं जो उत्परिवर्तन को ट्रिगर करती हैं। एसिंक्रोनस कार्यों को संभालते समय, जैसे कि एपीआई के लिए अनुरोध करना, एपीआई प्रतिक्रिया के साथ संबंधित म्यूटेशन को पेलोड के रूप में कॉल करने से पहले क्रियाओं का उपयोग किया जाता है। जैसे ही हम अपने कार्यों का निर्माण करेंगे, हमें इस परिदृश्य के लिए एक स्पष्ट कार्यान्वयन मिलेगा।
कार्रवाइयां बनाने से पहले, हम रेल सर्वर के लिए अपने सभी एचटीपी अनुरोध को संभालने के लिए एक्सियोस स्थापित करेंगे, जो इस प्रकार है:
npm install axios --save
एक actions.ts
बनाएं निम्न कोड स्निपेट के साथ स्टोर निर्देशिका में फ़ाइल करें:
//src/store/actions.ts
import { ActionContext, ActionTree } from "vuex";
import { Mutations, MutationType } from "./mutations";
import { State, Prescription, Data } from "./state";
import axios from "axios";
const apiUrl = "https://localhost:3000/prescriptions";
export enum ActionTypes {
GetPrescriptions = "GET_PRESCRIPTIONS",
SetCreateModal = "SET_CREATE_MODAL",
SetEditModal = "SET_EDIT_MODAL",
RemovePrescription = "REMOVE_PRESCRIPTION",
CreatePrescription = "CREATE_PRESCRIPTION",
UpdatePrescription = "UPDATE_PRESCRIPTION",
}
इसी तरह, उपरोक्त स्निपेट हमारे ऐप में क्रियाओं के सभी संभावित नामों को रखने के लिए एनम प्रतीक का उपयोग करता है।
इसके बाद, हम प्रत्येक एक्शन टाइप के लिए एक अनुबंध (प्रकार) की घोषणा इस प्रकार करेंगे:
//src/store/actions.ts
type ActionAugments = Omit<ActionContext<State, State>, "commit"> & {
commit<K extends keyof Mutations>(key: K, payload: Parameters<Mutations[K]>[1]): ReturnType<Mutations[K]>;
};
export type Actions = {
[ActionTypes.GetPrescriptions](context: ActionAugments): void;
[ActionTypes.SetCreateModal](context: ActionAugments): void;
[ActionTypes.SetEditModal](context: ActionAugments): void;
[ActionTypes.RemovePrescription](context: ActionAugments, Prescription: { id: number }): void;
[ActionTypes.CreatePrescription](context: ActionAugments, data: Data): void;
[ActionTypes.UpdatePrescription](context: ActionAugments, prescription: Prescription): void;
};
ActionAugments
type सभी कमिट्स को केवल उनके घोषित म्यूटेशन के लिए प्रतिबंधित करता है और पेलोड प्रकार की जांच करने के लिए भी।
इसके बाद, हम प्रत्येक एक्शन टाइप के लिए घोषित अनुबंध (प्रकार) को लागू करेंगे। नीचे दिए गए कोड को action.ts फ़ाइल में जोड़ें:
//src/store/actions.ts
export const actions: ActionTree<State, State> & Actions = {
async [ActionTypes.GetPrescriptions]({ commit }) {
commit(MutationType.SetLoading, true);
const response = await axios.get(apiUrl);
commit(MutationType.SetLoading, false);
commit(MutationType.SetPrescriptions, response.data);
},
async [ActionTypes.SetCreateModal]({ commit }) {
commit(MutationType.SetCreateModal, true);
},
async [ActionTypes.SetEditModal]({ commit }) {
commit(MutationType.SetEditModal, { showModal: true, prescriptionId: 1 });
},
//Optimistic update
async [ActionTypes.RemovePrescription]({ commit }, Prescription) {
if (Prescription != undefined) {
commit(MutationType.RemovePrescription, Prescription);
}
const response = await axios.delete(`${apiUrl}/${Prescription.id}`);
},
async [ActionTypes.CreatePrescription]({ commit, dispatch }, Prescription) {
const response = await axios.post(apiUrl, Prescription);
dispatch(ActionTypes.GetPrescriptions);
},
async [ActionTypes.UpdatePrescription]({ commit, dispatch }, Prescription) {
if (Prescription != undefined) {
commit(MutationType.UpdatePrescription, Prescription);
const response = await axios.patch(`${apiUrl}/${Prescription.id}`, Prescription);
dispatch(ActionTypes.GetPrescriptions);
}
},
};
यहां, हमने एक क्रिया चर बनाया जो सभी कार्यान्वित क्रियाओं को संग्रहीत करता है। इसी तरह, ActionTree<State> & Actions
यह सुनिश्चित करता है कि अनुबंध (type Actions
) सही ढंग से लागू किया गया है; अन्यथा, टाइपप्रति त्रुटि उत्पन्न करेगा।
हमने GetPrescriptions
. में अपने एसिंक्रोनस कॉल को Rails API एंडपॉइंट पर भी सेट किया है कार्रवाई की और SetPrescriptions
. को ट्रिगर किया पेलोड के रूप में प्रतिक्रिया डेटा के साथ उत्परिवर्तन प्रकार। हमने SetCreateModal
. भी सेट किया है , SetEditModal
, CreatePrescription
, UpdatePrescription,
और RemovePrescription
क्रियाएँ।
गेटर्स
गेटर्स वे विधियाँ हैं जो राज्य को उसके पहले पैरामीटर के रूप में प्राप्त करती हैं और स्टोर स्थिति से गणना की गई जानकारी लौटाती हैं।
एक getters.ts
बनाएं निम्न कोड स्निपेट के साथ स्टोर निर्देशिका में फ़ाइल करें:
//src/store/getters.ts
import { GetterTree } from "vuex";
import { State, Prescription } from "./state";
export type Getters = {
completedPrescriptionCount(state: State): number;
totalPrescriptionCount(state: State): number;
getPrescriptionById(state: State): (id: number) => Prescription | undefined;
};
export const getters: GetterTree<State, State> & Getters = {
completedPrescriptionCount(state) {
return state.prescriptions.filter((prescription) => prescription.completed).length;
},
totalPrescriptionCount(state) {
return state.prescriptions.length;
},
getPrescriptionById: (state) => (id: number) => {
return state.prescriptions.find((prescription) => prescription.id === id);
},
};
उपरोक्त कोड स्निपेट निम्नलिखित गेटर्स को परिभाषित करता है:
completedPrescriptionCount
- एक समारोह जो हमारे राज्य में पूर्ण किए गए नुस्खे की कुल संख्या प्राप्त करता है।totalPrescriptionCount
- एक समारोह जो हमारे राज्य में कुल नुस्खे प्राप्त करता है।getPrescriptionById
- एक फ़ंक्शन जो अपनी आईडी द्वारा एक नुस्खा प्राप्त करता है।
हमने गेटर्स में कुछ प्रकार की सुरक्षा भी जोड़ी है।
स्टोर
आइए हमारे state
को तार दें , mutations
, actions
, और getters
वैश्विक Vuex स्टोर के लिए। हम store/index.ts
को अपडेट करेंगे , इस प्रकार:
//src/store/index.ts
import { createStore, Store as VuexStore, CommitOptions, DispatchOptions, createLogger } from "vuex";
import { State, state } from "./state";
import { Mutations, mutations } from "./mutations";
import { Actions, actions } from "./actions";
import { Getters, getters } from "./getters";
export const store = createStore<State>({
plugins: process.env.NODE_ENV === "development" ? [createLogger()] : [],
state,
mutations,
actions,
getters,
});
export function useStore() {
return store as Store;
}
export type Store = Omit<VuexStore<State>, "getters" | "commit" | "dispatch"> & {
commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(key: K, payload: P, options?: CommitOptions): ReturnType<Mutations[K]>;
} & {
dispatch<K extends keyof Actions>(key: K, payload?: Parameters<Actions[K]>[1], options?: DispatchOptions): ReturnType<Actions[K]>;
} & {
getters: {
[K in keyof Getters]: ReturnType<Getters[K]>;
};
};
state
, mutations
, actions
, और getters
एक ऑब्जेक्ट को createStore
. में पास करके एक स्टोर बनाने की आवश्यकता होती है तरीका। विकास के दौरान, createLogger
प्लगइन राज्य (पिछली स्थिति और अगली स्थिति) को लॉग करता है और कंसोल में म्यूटेशन करता है। हमारे सभी एप्लिकेशन के घटकों में स्टोर तक पहुंच योग्य है; हमें इसे पूरे एप्लिकेशन में इंजेक्ट करने की आवश्यकता है। सौभाग्य से, Vue-CLI टूल ने पहले ही पूरे स्टोर को आयात कर लिया है और इसे एप्लिकेशन के Vue इंस्टेंस में पास कर दिया है।
Vuex Store को कंपोनेंट में एकीकृत करना
इस ट्यूटोरियल में, हमारे फ़्रंटएंड एप्लिकेशन में सभी घटकों को बनाने के लिए Vue 3 कंपोज़िशन API का उपयोग किया जाएगा।
ऐप्लिकेशन घटक
हमारे फ्रंटएंड को लॉन्च होते ही प्रिस्क्रिप्शन डेटा की एक सूची प्रस्तुत करनी चाहिए। हम GetPrescription
भेजेंगे घटक के mounted()
. के भीतर कार्रवाई जीवनचक्र हुक। एक घटक के भीतर स्टोर तक पहुंचने के लिए, useStore
हुक, जो हमारे स्टोर को लौटाता है, निष्पादित किया जाएगा।
//src/App.vue
<script lang="ts">
import { computed, defineComponent, onMounted } from "vue";
import PrescriptionList from "./components/PrescriptionList.vue";
import { useStore } from "./store";
import { ActionTypes } from "./store/actions";
export default defineComponent({
components: { PrescriptionList },
setup() {
const store = useStore();
const loading = computed(() => store.state.loading);
onMounted(() => store.dispatch(ActionTypes.GetPrescriptions));
const completedCount = computed(() => store.getters.completedPrescriptionCount);
const totalCount = computed(() => store.getters.totalPrescriptionCount);
return { loading, completedCount, totalCount };
},
});
</script>
<template>
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="https://bulma.io">
<img src="https://bulma.io/images/bulma-logo.png" width="112" height="28" />
</a>
</div>
<div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-start">
<a class="navbar-item"> Home </a>
<a class="navbar-item"> About </a>
</div>
</div>
</nav>
<div class="container mx-auto mt-4">
<h1 class="is-size-3 has-text-centered p-2 has-text-weight-bold is-success">Vet clinic Frontend</h1>
<h3 class="has-text-centered p-2">Manage records of treated livestock in your farm</h3>
<div v-if="loading">
<h3 class="has-text-centered mt-4">Loading...</h3>
</div>
<div v-else>
<p class="has-text-centered mt-2">{{ completedCount }} of {{ totalCount }} treated.</p>
<PrescriptionList />
</div>
</div>
</template>
<style>
@import "~bulma/css/bulma.css";
</style>
यहां, हमने तीन परिकलित गुण बनाए हैं:
completedCount
, जोcompletedPrescriptionCount
. को कॉल करता है पूर्ण उपचारों की कुल संख्या को पुनः प्राप्त करने के लिए गेट्टर विधि।totalCount
, जोtotalPrescriptionCount
. को कॉल करता है नुस्खे की कुल संख्या को पुनः प्राप्त करने के लिए गेट्टर विधि।loading
, जिसे राज्य की लोडिंग संपत्ति मिलती है।
Vue 3 कंपोजिशन एपीआई के साथ, टेम्प्लेट द्वारा आवश्यक विधियों और गुणों को टेम्प्लेट में एक्सेस करने के लिए वापस किया जाना चाहिए। ध्यान दें कि हमने loading, completedCount, and totalCount
को कैसे लौटाया है? ।
प्रिस्क्रिप्शनलिस्ट घटक
यह घटक बैकएंड से नुस्खों की सूची को पुनः प्राप्त करने और प्रिस्क्रिप्शन डेटा को चाइल्ड कंपोनेंट को पास करने के लिए जिम्मेदार होगा।
PrescriptionList.vue
बनाएं निम्नलिखित कोड के साथ घटक फ़ोल्डर के अंदर:
//src/components/PrescriptionList.vue
<template>
<table class="table is-hoverable is-striped">
<thead>
<tr>
<th><abbr title="Position">Prescription Id</abbr></th>
<th>Treated</th>
<th>Prescription</th>
<th><abbr title="Won">Prescribed By</abbr></th>
<th><abbr title="Drawn">Disease</abbr></th>
<th><abbr title="Drawn">Livestock</abbr></th>
<th><abbr title="Lost">Actions</abbr></th>
</tr>
</thead>
<tbody v-if="prescriptions">
<tr v-for="prescription in prescriptions" :key="prescription.id">
<PrescriptionListItem v-bind="prescription" />
</tr>
</tbody>
<tfoot>
<CreateModal v-show="showCreateModal"></CreateModal>
<button class="button is-success" @click="setModal">Create Prescription</button>
</tfoot>
</table>
<EditModal v-if="showEditModal" :id="editModalPrescriptionId"></EditModal>
<Prescription v-if="showPrescriptionModal" :id="showPrescriptionId"></Prescription>
</template>
<script>
import CreateModal from "./CreateModal";
import EditModal from "./EditModal";
import Prescription from "./Prescription";
import PrescriptionListItem from "./PrescriptionListItem";
import { defineComponent, computed } from "vue";
import { useStore } from "@/store";
import { MutationType } from "@/store/mutations";
export default defineComponent({
name: "Table",
components: {
CreateModal,
PrescriptionListItem,
Prescription,
EditModal,
},
setup() {
const store = useStore();
const setModal = () => {
store.commit(MutationType.SetCreateModal, true);
};
const showCreateModal = computed(() => store.state.showCreateModal);
const showEditModal = computed(() => store.state.showEditModal);
const editModalPrescriptionId = computed(() => store.state.editModalPrescriptionId);
const showPrescriptionModal = computed(() => store.state.showPrescriptionModal);
const showPrescriptionId = computed(() => store.state.showPrescriptionId);
const prescriptions = computed(() => store.state.prescriptions);
return { showCreateModal, setModal, prescriptions, showEditModal, showPrescriptionModal, editModalPrescriptionId, showPrescriptionId };
},
});
</script>
<style scoped>
table {
width: 100%;
}
.fa {
font-size: 1.2rem;
margin-left: 15px;
}
.fa:hover {
font-size: 1.4rem;
}
</style>
setModal
विधि उस उत्परिवर्तन को आमंत्रित करती है जो showCreateModal
sets सेट करता है राज्य में सही है, जिसके परिणामस्वरूप नुस्खे बनाने के लिए मोडल लॉन्च किया गया है।
हमने निम्नलिखित परिकलित गुण बनाए हैं:
showCreateModal
, जिसेshowCreateModal
. मिलता है राज्य की संपत्ति।showEditModal
, जिसेshowEditModal
. मिलता है राज्य की संपत्ति।showPrescriptionModal
, जिसेshowPrescriptionModal
. मिलता है राज्य की संपत्ति।prescription
, जो राज्य से नुस्खे की सूची प्राप्त करता है।showPrescriptionId
, जिसेshowPrescriptiond
. मिलता है राज्य की संपत्ति।editPrescriptionId
, जिसेeditPrescriptionId
. मिलता है राज्य की संपत्ति।
प्रिस्क्रिप्शन घटक
यह घटक PrescriptionList
. से एक प्रॉप के रूप में प्रिस्क्रिप्शन आईडी प्राप्त करेगा अवयव। आईडी प्रॉप्स का उपयोग getPrescriptionById
के माध्यम से संबंधित आईडी के साथ एक नुस्खा लाने के लिए किया जाएगा गेटर्स मेथड और ब्राउजर में प्रिस्क्रिप्शन प्रॉपर्टीज को रेंडर करते हैं।
निम्नलिखित कोड के साथ घटक फ़ोल्डर के अंदर Prescription.vue बनाएं:
//src/components/Prescription.vue
<template>
<div class="modal is-active">
<div class="modal-background"></div>
<div class="modal-content">
<h1>VIEW PRESCRIPTION</h1>
<div class="card">
<div class="card-content">
<div class="media">
<div class="media-content">
<p class="title is-4">Livestock: {{ prescription.livestock }}</p>
<p class="subtitle is-6"><b>Prescribed by:</b> {{ prescription.prescribed_by }}</p>
<p class="subtitle is-6"><b>Disease:</b> {{ prescription.disease }}</p>
</div>
</div>
<div class="content">
<p class="subtitle is-6">Prescription: {{ prescription.vet_prescription }}</p>
</div>
</div>
</div>
</div>
<button class="modal-close is-large" @click="closeModal" aria-label="close"></button>
</div>
</template>
<script lang="ts">
import { computed } from "vue";
import { useStore } from "@/store";
import { MutationType } from "@/store/mutations";
export default {
name: "PrescriptionModal",
props: {
id: { type: Number, required: true },
},
setup(props: any) {
const store = useStore();
const prescription = computed(() => store.getters.getPrescriptionById(Number(props.id)));
const closeModal = () => {
store.commit(MutationType.SetPrescriptionModal, {
showModal: false,
prescriptionId: undefined,
});
};
return { closeModal, prescription };
},
};
</script>
<style scoped>
h1 {
color: #ffffff;
text-align: center;
font-size: 2rem;
margin-bottom: 3rem;
}
</style>
closeModal
विधि SetPrescriptionModal
को कमिट करती है उत्परिवर्तन, जो showModal
. सेट करता है राज्य में संपत्ति झूठी है, जबकि prescription
computed property calls the getPrescriptionById
getter method to retrieve a prescription by its Id.
CreateModal Component
This component is responsible for creating prescriptions.
Create CreateModal.vue inside the components folder with the following code:
//src/components/CreateModal.vue
<template>
<div class="modal is-active">
<div class="modal-background"></div>
<div class="modal-content">
<form @submit.prevent="createPrescription">
<div class="field">
<label class="label">Prescribed By</label>
<div class="control">
<input v-model="prescribedBy" class="input" type="text" placeholder="Enter prescriber's name" />
</div>
</div>
<div class="field">
<label class="label">Prescription</label>
<div class="control">
<textarea v-model="prescription" class="textarea" placeholder="Enter prescription"></textarea>
</div>
</div>
<div class="field">
<label class="label">Disease</label>
<div class="control">
<input v-model="disease" class="input" type="text" placeholder="Enter name of disease" />
</div>
</div>
<div class="field">
<label class="label">Livestock</label>
<div class="control">
<input v-model="livestock" class="input" type="text" placeholder="Enter livestock" />
</div>
</div>
<div class="field is-grouped">
<div class="control">
<button type="submit" class="button is-link">Submit</button>
</div>
<div class="control" @click="closeModal">
<button class="button is-link is-light">Cancel</button>
</div>
</div>
</form>
</div>
<button class="modal-close is-large" @click="closeModal" aria-label="close"></button>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs } from "vue";
import { useStore } from "@/store";
import { Data } from "@/store/state";
import { MutationType } from "@/store/mutations";
import { ActionTypes } from "@/store/actions";
export default {
name: "CreateModal",
setup() {
const state = reactive({
prescription: "",
prescribedBy: "",
disease: "",
livestock: "",
});
const store = useStore();
const createPrescription = () => {
if (state.prescription === "" || state.prescribedBy === "" || state.disease === "" || state.livestock === "") return;
const prescription: Data = {
vet_prescription: state.prescription,
prescribed_by: state.prescribedBy,
disease: state.disease,
livestock: state.livestock,
};
store.dispatch(ActionTypes.CreatePrescription, prescription);
state.prescription = "";
state.prescribedBy = "";
state.disease = "";
state.livestock = "";
};
const closeModal = () => {
store.commit(MutationType.SetCreateModal, false);
};
return { closeModal, ...toRefs(state), createPrescription };
},
};
</script>
The createPrescription
method dispatches an action that makes a post request to the server, thereby creating a new prescription, while the closeModal
method commits the SetPrescriptionModal
mutation (which sets the showModal property in the state to false).
Working with forms and input element requires two-way data binding, and as such, we used Vue 3’s reactive
method to store values used in the input fields.
Note:When using reactive
, we need to use toRefs
to convert the reactive object to a plain object, where each property on the resulting object is a ref pointing to the corresponding property in the original object.
EditModal Component
This component is responsible for updating prescriptions. Its logic is similar to the CreatePrescription
component we discussed in the previous section.
Create EditModal.vue inside the components folder with the following code:
//src/components/EditModal.vue
<template>
<div class="modal is-active">
<div class="modal-background"></div>
<div class="modal-content">
<form @submit.prevent="updatePrescription">
<h1>Edit Modal</h1>
<div class="field">
<label class="label">Prescribed By</label>
<div class="control">
<input v-model="prescribedBy" class="input" type="text" placeholder="Enter prescriber's name" />
</div>
</div>
<div class="field">
<label class="label">Prescription</label>
<div class="control">
<textarea v-model="prescription" class="textarea" placeholder="Enter Prescription"></textarea>
</div>
</div>
<div class="field">
<label class="label">Disease</label>
<div class="control">
<input v-model="disease" class="input" type="text" placeholder="Enter name of disease" />
</div>
</div>
<div class="field">
<label class="label">Livestock</label>
<div class="control">
<input v-model="livestock" class="input" type="text" placeholder="Enter livestock" />
</div>
</div>
<div class="field is-grouped">
<div class="control">
<button type="submit" class="button is-link">Submit</button>
</div>
<div class="control" @click="closeModal">
<button class="button is-link is-light">Cancel</button>
</div>
</div>
</form>
</div>
<button class="modal-close is-large" @click="closeModal" aria-label="close"></button>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs, computed, onMounted } from "vue";
import { useStore } from "@/store";
import { Prescription } from "@/store/state";
import { MutationType } from "@/store/mutations";
import { ActionTypes } from "@/store/actions";
export default {
name: "EditModal",
props: {
id: { type: Number, required: true },
},
setup(props: any) {
const state = reactive({
prescription: "",
prescribedBy: "",
disease: "",
livestock: "",
});
const store = useStore();
const setFields = () => {
const prescription = store.getters.getPrescriptionById(Number(props.id));
if (prescription) {
console.log("prescription si kolo", prescription);
state.prescription = prescription.vet_prescription;
state.prescribedBy = prescription.prescribed_by;
state.disease = prescription.disease;
state.livestock = prescription.livestock;
}
};
onMounted(() => {
setFields();
});
const updatePrescription = () => {
if (state.prescription === "" || state.prescribedBy === "" || state.disease === "" || state.livestock === "") return;
const prescription: Prescription = {
id: props.id,
vet_prescription: state.prescription,
prescribed_by: state.prescribedBy,
disease: state.disease,
livestock: state.livestock,
completed: false,
editing: false,
};
store.dispatch(ActionTypes.UpdatePrescription, prescription);
state.prescription = "";
state.prescribedBy = "";
state.disease = "";
state.livestock = "";
};
const closeModal = () => {
store.commit(MutationType.SetEditModal, { showModal: false, prescriptionId: undefined });
};
return { closeModal, ...toRefs(state), updatePrescription };
},
};
</script>
<style scoped>
label {
color: #ffffff;
}
h1 {
color: #ffffff;
text-align: center;
font-size: 2rem;
margin-bottom: 3rem;
}
</style>
The createPrescription
method dispatches an action that makes a put request to the server, thereby updating an existing prescription by its ID, while the closeModal
method commits the SetPrescriptionModal
mutation that sets the showModal
property in the state to false. Calling the setFields
method on the onMounted
lifecycle hook triggers the getPrescriptionById
getters method to fetch a prescription from the store by its ID and then updates the properties in the reactive object with the fetched prescription properties as soon as the component is mounted on the DOM.
Launching the Final Project
In the root directory of your Rails API server, run the following command to start the server:
rails server
Now, you can run the frontend application with the following command:
npm run serve
Finally, your application should be as follows:
निष्कर्ष
We have built a CRUD API server with Rails and our frontend application on Vue 3 composition API and Vuex, all running on different servers while integrating both stacks to build a fullstack web application. I hope you have learned a great deal from this tutorial. Please reach out in the comment section below if you have any questions or suggestions. Here is the GitHub repo for the full-stack application built in this tutorial.