يهدف هذا المشروع إلى تخفيف الألم في تطوير SPA من خلال تنفيذ نمط مبدئي لنمذجة حالة التطبيق بطريقة غير محددة الإطار وسهلة الاختبار وصديقة للمطورين. يسمح لك Sparix بتغليف الحالة في متاجر آمنة للنوع، وتحديد التحويلات التي يمكن أن تحدث في الحالة المذكورة. لا يمكن للتحديث أبدًا تغيير الحالة، وبدلاً من ذلك يقوم بإنشاء نسخة محولة جديدة من الحالة (تمامًا مثل مخفض الإعادة). أصبح تسلسل الحالات المحولة متاحًا للعامة باعتباره RxJS Observable<State>
.
تتم كتابة Sparix بلغة TypeScript، وكذلك نماذج التعليمات البرمجية. يتم توزيعها كمكتبة JavaScript مع تعريفات النوع المضمنة في وحدة NPM، تمامًا مثل RxJS.
$ npm i -S sparix rxjs
import { Store } from 'sparix'
import { add } from 'ramda'
export interface CounterState {
count : number
}
const initialState : CounterState = {
count : 0
}
export class Counter extends Store < CounterState > {
constructor ( ) {
super ( initialState )
}
increment ( ) {
// ALL THESE ARE EQUIVALENT
this . update ( state => { count : state . count + 1 } )
this . updateState ( { count : val => val + 1 } )
this . updateState ( { count : add ( 1 ) } ) // Using Ramda's automatically curryied functions
}
}
import { Counter , CounterState } from './counter'
const counter = new Counter ( )
// Recommended way
const state$ : Observable < CounterState > = counter . state$
const count$ : Observable < number > = counter . map ( state => state . count )
// Alternative way (useful for testing)
expect ( counter . currentState . count ) . toEqual ( 0 )
counter . increment ( )
expect ( counter . currentState . count ) . toEqual ( 1 )
أولاً، إنه نمط. ثانيًا، إنه تطبيق يعتمد على RxJS. يعد التنفيذ تافهًا للغاية، ولن يستغرق الأمر سوى بضع ساعات لإعادة كتابته باستخدام مكتبة تفاعلية أخرى. ومع ذلك، نظرًا لأن React وAngular2 سيهيمنان على عالم SPA، وبما أن الأخير يأتي مع RxJS، فمن المنطقي استخدام هذه المكتبة للتنفيذ المرجعي لـsparix.
في sparix، تم تصميم الحالة على أنها Observable<State>
، وهي عبارة عن تيار ثابت من انتقالات الحالة.
تظل واجهة برمجة تطبيقات المتجر بسيطة، ويتم تغليف كل المنطق المعقد وإخفائه من الخارج، تمامًا كما تفعل مع البرمجة الكائنية القديمة الجيدة. لاختبار متجر، كل ما عليك فعله هو محاكاة أحد المدخلات (عن طريق استدعاء إحدى طرقه العامة) والتحقق من مخرجاته (الحالة).
يلتزم Sparix تمامًا بمبدأ الإعادة (أو بالأحرى مبدأ Elm Architecture) حيث يتم تعريف تحويلات الحالة على أنها وظائف خالصة لا تؤدي إلى تغيير الحالة السابقة.
في الإعادة، عندما تحتاج إلى تحديث الحالة، يمكنك إرسال إجراء. ولكن إذا نظرت عن كثب، قد تدرك أن الإجراءات يمكن تصنيفها إلى فئتين:
ادعائي هو أن الإجراءات تعتبر آلية ثقيلة جدًا عندما يكون الهدف ببساطة هو تحديث حالة متجر واحد (كما هو الحال في معظم الحالات). في sparix، يمكن للمتجر تحديث حالته مباشرة دون أي احتفال أكثر من:
// Increment counter
this . update ( state => ( {
counter : state . counter + 1
} ) )
هناك طريقة أكثر دقة وتصريحًا لكتابة مُحدِّثات الحالة هذه:
this . updateState ( {
counter : prevCounter => prevCounter + 1
} )
أو حتى أفضل:
const increment = value => value + 1
this . updateState ( {
counter : increment
} )
حسنًا، في الواقع يجب عليك الاستفادة من الكاري التلقائي الخاص برامدا:
import { add } from 'ramda'
this . updateState ( {
counter : add ( 1 )
} )
أحب أن أفكر في محدثي الحالة كإجراءات مجهولة المصدر. في الإعادة، سيكون الأمر مثل إرسال المخفض. ولكن ماذا عن المبدعين العمل؟ حسنًا، نحن لسنا بحاجة إليهم حقًا:
const increment = val => val + 1
class SomeStore extends Store < SomeState > {
// constructor
incrementCounter ( ) {
this . updateState ( {
counter : increment
} )
}
}
هنا، تعد طريقة incrementCounter()
جزءًا من واجهة برمجة التطبيقات العامة للمتجر. لم تعد بحاجة إلى إرسال إجراء عالمي تم إنشاؤه بواسطة منشئ الإجراء. فقط اتصل بالطريقة!
يدور Sparix حول نمذجة جوهر تطبيقك. ولكن ما هو جوهر؟ أو بالأحرى، ما الذي لا يوجد في القلب؟
يجب أن يكون جوهر التطبيق ملحدًا. ملحد للأطر وقواعد البيانات، ملحد لطبقة العرض، ملحد لآلية جلب البيانات والبروتوكولات. ينبغي أن يكون ملحدًا لكل شيء .
لا يعرف جوهر التطبيق شيئًا عن HTML أو DOM أو Angular أو React أو التخزين المحلي أو HTTP أو WebSockets.. ولا يعرف حتى أنه يعيش في متصفح الويب! يجب أن يكون نفس جوهر التطبيق قابلاً لإعادة الاستخدام في تطبيقات Cordova أو NativeScript أو Electron دون تغيير سطر واحد من التعليمات البرمجية !
إذن ماذا تضع في القلب؟ الجواب بسيط للغاية: كل شيء آخر ! فإذا كان من الممكن أن يكون جزءًا من القلب، فيجب أن يكون جزءًا من القلب. يجب تصميم كل منطق الأعمال، وتحويلات البيانات، ومنطق التفاعل، على أنه جوهر التطبيق. ولا ينبغي أن يعتمد أي من ذلك على أي شيء آخر غير لغة البرمجة التي استخدمت في تصميمه.
لذا عد إلى سباركس. سيساعدك ذلك على تصميم نواة تطبيق لا تعتمد على مكتبات وأطر عمل تابعة لجهات خارجية، مع استثناءين هما RxJS وsparix نفسها. لكن هذه ليست مشكلة كبيرة. إن العناصر القابلة للملاحظة في طريقها لأن تصبح ميزة ECMAScript قياسية، وsparix هي مكتبة غير تدخلية، مما يجعل من السهل تصميم مجموعة فرعية فقط من جوهر تطبيقك باستخدامها.