โครงการนี้มีจุดมุ่งหมายเพื่อบรรเทาความเจ็บปวดในการพัฒนา SPA โดยการนำรูปแบบความคิดเห็นไปใช้ในการสร้างแบบจำลองสถานะของแอปพลิเคชันในลักษณะที่ไม่เชื่อเรื่องกรอบงาน ทดสอบได้ง่าย และเป็นมิตรกับนักพัฒนา Sparix ช่วยให้คุณสามารถสรุปสถานะในร้านค้าประเภทที่ปลอดภัย และกำหนดการเปลี่ยนแปลงที่อาจเกิดขึ้นกับสถานะดังกล่าว การอัปเดตไม่สามารถเปลี่ยนสถานะได้ แต่จะสร้างอินสแตนซ์ที่แปลงใหม่ของสถานะแทน (เช่นเดียวกับตัวลด Redux) ลำดับสถานะที่แปลงแล้วจะถูกเปิดเผยต่อสาธารณะในรูปแบบ 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 การใช้งานค่อนข้างเล็กน้อย และใช้เวลาเพียงสองสามชั่วโมงในการเขียนใหม่ด้วยไลบรารีแบบโต้ตอบอื่น อย่างไรก็ตาม เนื่องจากโลกของ SPA ถูกครอบงำโดย React และ Angular2 และเนื่องจากอย่างหลังมาพร้อมกับ RxJS จึงสมเหตุสมผลที่จะใช้ไลบรารีนี้สำหรับการดำเนินการอ้างอิงของ sparix
ใน sparix สถานะจะถูกจำลองเป็น Observable<State>
ซึ่งเป็นกระแสการเปลี่ยนแปลงสถานะที่ไม่เปลี่ยนรูป
API ของ Store นั้นเรียบง่าย และตรรกะที่ซับซ้อนทั้งหมดนั้นถูกห่อหุ้มและซ่อนไว้จากภายนอก เช่นเดียวกับที่คุณทำกับการเขียนโปรแกรมเชิงวัตถุแบบเก่า ในการทดสอบ Store สิ่งที่คุณต้องทำคือจำลองอินพุต (โดยการเรียกหนึ่งในวิธีสาธารณะ) และตรวจสอบเอาต์พุต (สถานะ)
Sparix ปฏิบัติตามหลักการ redux อย่างสมบูรณ์ (หรือมากกว่านั้นคือหลักการของสถาปัตยกรรม Elm) โดยที่การแปลงสถานะถูกกำหนดให้เป็นฟังก์ชันล้วนๆ ซึ่งไม่กลายพันธุ์ในสถานะก่อนหน้า
ใน redux เมื่อคุณต้องการอัพเดตสถานะ คุณจะต้องส่งการดำเนินการ แต่หากคุณมองให้ละเอียด คุณอาจพบว่าการดำเนินการสามารถจัดเรียงได้เป็น 2 ประเภท :
คำกล่าวอ้างของฉันคือการดำเนินการเป็นกลไกที่หนักเกินไปเมื่อเป้าหมายเป็นเพียงการอัปเดตสถานะของร้านค้าเดียว (เช่นในกรณีส่วนใหญ่) ใน 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
} )
ที่จริงแล้วคุณควรใช้ประโยชน์จากการแกงอัตโนมัติของ Ramda:
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()
เป็นส่วนหนึ่งของ API สาธารณะของ Store คุณไม่จำเป็นต้องส่งการดำเนินการระดับโลกที่สร้างโดยผู้สร้างการกระทำอีกต่อไป เพียงเรียกวิธีการ !
Sparix เป็นเรื่องเกี่ยวกับการสร้างแบบจำลองแกนหลักของแอปพลิเคชันของคุณ แต่หลักคืออะไร? หรือมากกว่านั้น มีอะไรที่ไม่อยู่ในแกนกลาง ?
แกนแอปพลิเคชันควรไม่เชื่อเรื่องพระเจ้า ไม่เชื่อเรื่องเฟรมเวิร์กและฐานข้อมูล ไม่เชื่อเรื่องเลเยอร์การนำเสนอ ไม่เชื่อเรื่องกลไกและโปรโตคอลการดึงข้อมูล มันควรจะไม่เชื่อเรื่องพระเจ้ากับ ทุกสิ่ง
แกนแอปพลิเคชันไม่ทราบเกี่ยวกับ HTML, DOM, Angular หรือ React, Local Storage, HTTP หรือ WebSockets .. มันไม่รู้ด้วยซ้ำว่ามันอยู่ในเว็บเบราว์เซอร์! แอปพลิเคชันคอร์เดียวกันควรสามารถนำมาใช้ซ้ำได้ในแอป Cordova, NativeScript หรือ Electron โดยไม่ต้องเปลี่ยนโค้ดแม้แต่บรรทัดเดียว !
แล้วคุณใส่อะไรลงไปในแกน? คำตอบนั้นค่อนข้างง่าย: อย่างอื่นทั้งหมด ! หากสามารถเป็นส่วนหนึ่งของแกนกลางได้ ก็ควรเป็นส่วนหนึ่งของแกนกลางด้วย ตรรกะทางธุรกิจทั้งหมด การแปลงข้อมูล ตรรกะการโต้ตอบ ควรได้รับการจำลองเป็นแกนหลักของแอปพลิเคชัน และ สิ่งเหล่านี้ไม่ ควรขึ้นอยู่กับสิ่งอื่นใดนอกจากภาษาการเขียนโปรแกรมที่ใช้ในการจำลองมัน
กลับมาที่สปาริกซ์อีกครั้ง ซึ่งจะช่วยคุณสร้างโมเดลแกนแอปพลิเคชันที่ไม่ขึ้นอยู่กับไลบรารีและเฟรมเวิร์กของบริษัทอื่น โดยมีข้อยกเว้นสองประการคือ RxJS และ sparix เอง แต่นั่นไม่ใช่ปัญหามากนัก สิ่งที่สังเกตได้กำลังจะกลายเป็นคุณสมบัติ ECMAScript มาตรฐาน และ sparix เป็นไลบรารีที่ไม่ล่วงล้ำ ซึ่งทำให้ง่ายต่อการสร้างแบบจำลองเฉพาะชุดย่อยของแกนแอปพลิเคชันของคุณ