تايب سكريبت - عدة نسخ لتطبيق Svelte مع المتاجر (بدون Redux)
ملاحظة: تم الرد من قبل النفس
لذلك، بشكل افتراضي، هناك ثلاث طرق رئيسية في Svelte يمكنك استخدامها لتمرير البيانات بين المكونات المختلفة.
1. الواضح، باستخدام الدعائم
تمرير البيانات من الأصل إلى الطفل.
- نقل البيانات في اتجاه واحد فقط.
- يتم تمريره بين مكونين أب وابن فقط. يجب أن يكون طفلاً مباشراً.
2. إعداد واستخدام السياق
يمكن تمرير البيانات من المكون الأب إلى أي مكون فرعي عميق.
- تدفق البيانات في اتجاه واحد فقط
- لا يمكن تمرير البيانات من خارج التسلسل الهرمي للأب والابن.
- يجب إعداده عند بدء مكون الأب.
3. باستخدام متجر Svelte
يمكن تعيين وتحديث واستخدام/الاشتراك في البيانات من/في أي ملف أو مكون.
- إذا كانت هناك عدة نسخ من نفس التطبيق تعمل، سيقوم المتجر بحفظ قيمة واحدة فقط من أي من النسخ.
storeVar.set()يحدد القيمة من أي من النسخ اعتمادًا على وقت تحميل الصفحة.storeVar.update()يحدد القيمة من آخر نسخة.
هدف
إعداد تطبيق Svelte لاكتشاف عدة أكواد تضمين مخصصة من ملف الفهرس الرئيسي وتشغيل عدة نسخ من التطبيق. سيكون لدى كود التضمين بيانات إضافية - حجم الفيديو، نسبة العرض إلى الارتفاع، إلخ. لذا ستتغير واجهة كل نسخة بناءً على خصائص كود التضمين (المرسلة كخصائص إلى التطبيق). في واجهة المستخدم، قد ينقر المستخدم على إجراءات مختلفة مثل أحجام الشاشة وبناءً على ذلك، سأضطر لتحديث قيم التطبيق (الخصائص المرسلة من الفهرس إلى التطبيق) لتلك النسخة فقط وليس للنسخ الأخرى.
مشكلة
من المشاكل المذكورة أعلاه، إما أنني لا أستطيع تمرير القيم أو تحديثها لاحقًا في المكونات (المشكلة 2.2، 2.3) أو أن المخزن لا يحفظ قيم كل حالة (3.1)
الإجابة رقم 1
الحل (مختبر ويعمل)
بشكل أساسي، قمت بإنشاء مصفوفة من الكائنات تحتوي على id وdata لكل مثيل. استخدم update() بدلاً من set(). أقوم بتصفية كائن المثيل الجديد من المصفوفة قبل إضافة البيانات الجديدة لنفس المثيل.
كود (تايب سكريبت)
package.json
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.30",
"@tsconfig/svelte": "^2.0.1",
"autoprefixer": "^10.4.7",
"cssnano": "^5.1.10",
"postcss": "^8.4.14",
"svelte": "^3.44.0",
"svelte-check": "^2.2.7",
"svelte-preprocess": "^4.9.8",
"tailwindcss": "^3.0.24",
"tslib": "^2.3.1",
"typescript": "^4.5.4",
"vite": "^2.9.9"
},
"dependencies": {
"swiper": "^8.2.2"
}
فايل index.html
<body>
<custom-element
id="id_custom_element_987654321"
videoid="987654321"
size="7"
></custom-element>
<script type="module" src="/src/main.ts"></script>
<custom-element
id="id_custom_element_123456789"
videoid="123456789"
size="3"
></custom-element>
<script type="module" src="/src/main.ts"></script>
</body>
رئيسي.ts
const embedElements = document.querySelectorAll(
"custom-element"
);
const app = embedElements.forEach((each) => {
// @ts-ignore
const elementId = each.attributes.id;
// @ts-ignore
const videoid = each.attributes.videoid;
if (elementId && videoid) {
return new App({
target: each,
props: {
embedElementId: elementId.value,
embedVideoid: videoid.value,
},
});
}
});
export default app;
helpers.ts
// Svelte helpers
export type CustomStoreFormatType<K> = {
videoid: string;
data: K;
};
export type StoreKeyType<L> = Writable<CustomStoreFormatType<L>[]>;
export const custom_updateStore = <T>(
storeKey: StoreKeyType<T>,
updateValue: CustomStoreFormatType<T>
) => {
storeKey.update((old) => [
...old.filter(
(e) => e.videoid !== updateValue.videoid
),
{ ...updateValue },
]);
};
export const custom_getStore = <T>(
storeKey: CustomStoreFormatType<T>[],
videoid: string
) => storeKey.find((e) => e.videoid === videoid);
store.ts
type CommonCustomStoreFormatType<T> = Array<CustomStoreFormatType<T>>;
export const store_videoComments = writable<
CommonCustomStoreFormatType<Array<VideoCommentsType>>
>([]);
App.svelte
// passed props
export let embedElementId: string;
export let embedVideoid: string;
setContext("contxt_videoid", embedVideoid);
let videoComments = fetchvideoComments(embedVideoid);
videoComments.then(({ data }) => {
custom_updateStore<VideoCommentsType[]>(store_videoComments, {
videoId: data.id,
data: data.comments,
});
});
</script>
<main>
{#await videoData}
<LoaderCircular --color="green" />
{:then { data }}
<Video />
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
</main>
أي مكون آخر (الحصول على قيمة نسخة المتجر)
import { store_videoComments } from "./store";
const videoId = getContext("contxt_videoId");
let { data } = custom_getStore(
$store_videoComments,
videoId as string
);
الإخراج - تسجيل
$store_videoComments
[
{
"videoId": "987654321",
"data": "[data1,data2,data3]"
},
{
"videoId": "123456789",
"data": "[data63,data74,data88]"
}
]
كما ترى من السجل، يتم تخزين جميع قيم مثيلات التطبيق. أخبرني في التعليقات إذا وجدت أي مشاكل في الطريقة أعلاه أو تعرف/تستخدم بديل أفضل لكل هذا.
ملاحظة:
- كنت أريد الحفاظ على حجم البناء منخفضًا قدر الإمكان، لذلك لم أبحث عن أي حزم طرف ثالث أو أدرجها لمعالجة المشكلة.
- لم أستخدم SvelteKit
- نفس المنشور على github-svelte-discussion
