فرید ذوالقدر
فرید ذوالقدر
خواندن ۳ دقیقه·۱ سال پیش

جایگزینی Signal با RXJS در انگولار

سلام، دلتون شاد و لبتون پرخنده :))
از وقتی که سیگنال مطرح شده یه طوفانی توی انگولار واسه طرفدارهای خودش راه انداخته، منم گفتم این وسط بی نصیب نذارم و یه مقاله آموزشی درباره جایگزینیش با rxjs برم.
به کمک سیگنال فقط node DOM که نیاز دارن به روز رسانی بشن، تغییر می کنن و این خودش باعث افزایش سرعت انگولار میشه! دیگه نیازی به pipe هم ندارید!
هر برنامه انگولار متوسط تا پیچیده، کاربردهای rxjs زیادی دارد. اگرچه rxjs یک کتابخانه بسیار مفید است، اما درک آن برای بسیاری از توسعه دهندگان ممکن آسون نباشه. اما با سیگنال ها می توانیم به طور بالقوه از شر اکثر کدهای rxjs خلاص شیم. این باعث می شود که angular از توسعه دهندگان جدیدی استقبال بیشتری بکنه و خوانایی کلی پایه کد را افزایش بده. خب پرچونگی بسه بریم سراغ جایگزین کردن!


//Example behaviourSubject usage const subject = new BehaviourSubject(0); subject.getValue(); subject.next(1); subject.subscribe((data) => { console.log(data) }) //Example signal usage const sig = signal(0); sig() sig.set(1) effect(() => { console.log(sig()) })

به همین سادگی اومدیم کدهامون BehaviourSubject با signal عوض کردیم! سیگنال ها همیشه همگام sync هستند. بنابراین شما همیشه می توانید مقدار فعلی یک سیگنال را دریافت کنید.دریافت مقدار فعلی سیگنال بسیار ساده است اما برای Observable نه چندان زیاد. با اطمینان از BehaviourSubject، همیشه می‌توانیم مقدار فعلی را به صورت همگام دریافت کنیم، اما وقتی هر نوع عملیاتی را انجام دادیم، این قابلیت را از دست می‌دهیم.

const number = new BehaviourSubject(0); number.getValue(); const isOdd = number.pipe(map((data) => data % 2 ? true : false)); isOdd.getValue() //<--- we can not do this const numberSignal = new BehaviourSubject(0); numberSignal(); const isOddSignal = computed(() => numberSignal() % 2 ? true : false); isOddSignal() //<--- we can do this

برخلاف Observable سیگنال نیازی به distinctUntilChange یا shareReplay برای چندپخشی نداره.
حالا این وسط یه سوالی پیش میاد: ما به rxjs نیاز نداریم؟
خوب، نه دقیقا. زیرا سیگنال همیشه همگام است. آنها کاندیدای بسیار خوبی برای ذخیره وضعیت ها یا مدل view هستند. اما سیگنال‌ها کاندیدای خوبی برای موارد غیرهمگام، مانند رویدادها یا تماس‌های XHR نیستند.
توی یه مثال ساده دیگه می خوام یه دستور سرچ ساده به کمک rxjs بسازم:

const searchValue$: Observable<string> //lets assume this is comes from input const result$ = searchValue$.pipe( debounceTime(300), distinctUntilChanged(), switchMap((input) => { return this.http.get('/seach?' + input) }) )

برای تبدیل این کد به سیگنال میایم اول سیگنال به observable تبدیل می کنیم بعدش دوباره به سیگنال برش می گردونیم:

const searchValue: Signal<string> const searchValue$ = fromSignal(searchValue); //convert signal to observable const result$ = searchValue$.pipe( debounceTime(300), distinctUntilChanged(), switchMap((input) => { return this.http.get('/seach?' + input) }) ) const result = fromObservable(result$) //convert observable back to signal

در دنیایی که سیگنال‌ها به طور کامل پذیرفته می‌شوند، ممکن است rxj‌ها را فقط برای چنین مواردی به‌طور کم استفاده کنیم. ادامه دادن پریدن بین سیگنال و روش نوشتن کد rxjs کمی سخت است. اما شاید بتوانیم rxjs را حتی برای چنین مواردی به طور کامل حذف کنیم؟

const searchValue: Signal<string> const debouncedSearchValue = signal(searchValue()); const results: WritableSignal<Result[]> = signal([]) /** This effect add debounced search term in a new signal */ effect(() => { const search = searchValue(); const timeout = setTimeout(() => { debouncedSearchValue.set(search) }); return () => { clearTimeout(timeout) } }) /** This effect uses debounceSearchValue instead of searchValue to trigger api call */ effect(() => { const subscription = this.http.get('/seach?' + debouncedSearchValue()) .subscribe((res) => { results.set(res) }) return () => { subscription.unsubscribe() } })

حالا بیایم این کد یه مقدار تمیزترش کنیم:

const searchValue: Signal<string> const debounceSearchValue = debouncedSignal(searchValue); const results: WritableSignal<Result[]> = signal([]); effect(() => { const subscription = this.http.get('/seach?' + debouncedSearchValue()) .subscribe((res) => { results.set(res) }) return () => { subscription.unsubscribe() } })

تابع debouncedSignal استفاده شده در بالا به این شکل است:

function debouncedSignal<T>(input: Signal<T>): Signal<T> { const debounceSignal = signal(input()); effect(() => { const value = input(); const timeout = setTimeout(() => { debounceSignal.set(value) }); return () => { clearTimeout(timeout) } }); return debounceSignal }

اما جمله آخر : rxjs اختصار را به ارمغان می‌آورد و سیگنال‌ها خواندن را آسان‌تر می‌کنند.



در اینجا به آخر مقاله رسیدیم، از اینکه منو توی این مقاله همراهی کردین ممنونم این مقاله یه مختصری از این مقاله بودش.
ممنون از توجهتون
:))

angularrxjssignal
شاید از این پست‌ها خوشتان بیاید