سیگنال های زاویه ای: یک مدل ذهنی جدید برای واکنش پذیری، نه فقط یک API جدید

سیگنال های زاویه ای فقط یک ویژگی دیگر نیستند. آنها روشی متفاوت برای تفکر در مورد جریان داده را نشان می دهند. اگر از پیوندهای RxJS یا استاندارد @Input() / @Output() میآیید، ممکن است سیگنالها را به عنوان یک نحو سادهتر برای مقادیر قابل مشاهده در نظر بگیرید. با این حال، این مثل این است که بگوییم یک ویولن فقط یک ویولن سل کوچکتر است. شکل ساز بر نوع موسیقی شما تأثیر می گذارد.
در این مقاله، من مستندات را تکرار نمیکنم یا شما را از طریق مثال ضد دیگری راهنمایی نمیکنم. در عوض، من یک روش جدید از تفکر را معرفی می کنم که سیگنال ها را فعال می کند، همراه با برخی از چالش های واقعی که هنگام استفاده از آنها در تولید با آن مواجه شدم.
سیگنال ها به عنوان متغیرهای واکنشی، نه جریان ها
سیگنال ها را به عنوان متغیرهای واکنشی در نظر بگیرید، نه جریان های داده. این تغییر کلیدی در دیدگاه است. در RxJS، ما معمولاً مقادیر را در جریان پایین میآوریم، آنها را ترکیب میکنیم و با عوارض جانبی از طریق subscribe() پاسخ میدهیم. سیگنال ها این مفهوم را تغییر می دهند. شما از آنها مانند متغیرها می خوانید . Angular به طور خودکار وابستگی ها را ردیابی می کند و واکنش ها را تحریک می کند.
در اینجا بهترین روشی است که من سیگنال ها را در کد توضیح می دهم:
const firstName = signal('John'); const lastName = signal('Doe'); const fullName = computed(() => `${firstName()} ${lastName()}`);در این مثال، نام کامل زمانی که firstName یا lastName تغییر می کند به طور خودکار دوباره محاسبه می شود. نیازی نیست که از نظر نقشه، ترکیب آخرین، یا منطق نابود کردن فکر کنید. شما فقط روابط خود را اعلام می کنید.
اگر شبیه Vue یا SolidJS باشد، تصادفی نیست.
Gotcha شماره 1: وابستگی های ضمنی می توانند نتیجه معکوس داشته باشند
هنگامی که از یک سیگنال در داخل یک computed() یا effect()، آهنگ های Angular را می خوانید که به عنوان یک وابستگی خوانده می شوند. اما زمانی که شما از آن خواندهها آگاه نباشید، ممکن است به سرعت اشتباه شود.
let counter = signal(0); const doubled = computed(() => { console.log('Recomputing...'); return counter() * 2; });ممکن است انتظار داشته باشید که این تنها زمانی اجرا شود که شمارنده تغییر کند، اما اگر به طور تصادفی سیگنال دیگری را در همان تابع بخوانید (مثلاً یک پرچم ورود)، آن نیز به یک وابستگی تبدیل میشود. ناگهان، تغییر پرچم حالت اشکال زدایی شروع به محاسبه مجدد منطق ریاضی شما می کند.
نکته: منطق محاسبه شده و اثر را محدود و قطعی نگه دارید. در غیر این صورت، بهروزرسانیهای فانتومی خواهید داشت که نمیتوانید اشکال زدایی کنید.
سیگنال ها در مقابل RxJS: جایی که سیگنال ها می درخشند - و جایی که نمی درخشند
بیایید واضح بگوییم: سیگنال ها جایگزین RxJS نمی شوند. آنها برای کار در کنار آن طراحی شده اند. اما درک زمان استفاده از هر یک بسیار مهم است.
| استفاده از مورد | سیگنال ها را ترجیح دهید | RxJS را ترجیح دهید |
| وضعیت مؤلفه محلی | ✓ | X |
| داده های UI مشتق شده | ✓ | X |
| جریان رویداد (مثلاً تایپ کاربر) | X | ✓ |
| وضعیت مشترک در بین ماژول ها (از طریق سیگنال های سرویس) | ✓ | ✓ |
| جریانهای ناهمگام پیچیده با تلاشهای مجدد | X | ✓ |
سیگنال ها در طول زمان در ارزش مدل سازی برتری دارند. RxJS در مدل سازی رویدادها در طول زمان برتری می یابد.
Gotcha شماره 2: سیگنال های محاسبه شده آنطور که شما فکر می کنید ذخیره نمی شوند
یک چیز شگفتانگیز که من کشف کردم: computed() مانند useMemo() React یا حتی آنطور که ممکن است از یک گیرنده انتظار داشته باشید، حافظهگذاری نمیکند.
هر بار که از یک سیگنال ()computed خوانده میشوید، اگر ورودیهای آن تغییر کرده باشند، منطق دوباره اجرا میشود. اما اگر چندین بار در یک الگو با آن تماس بگیرید (مثلاً در *ngIf و دوباره در {{ }})، ممکن است هزینه را بیش از یک بار بپردازید.
نکته: اگر یک محاسبه گران است، آن را در یک const محلی در کلاس کامپوننت ذخیره کنید و فقط به آن در قالب ارجاع دهید. یا آن را در سیگنال دیگری بپیچید.
بازاندیشی در شکل حالت: سیگنالها عاشق تخت هستند، نه عمیق
در انگولار کلاسیک با سرویسها و RxJS، مدل کردن حالت به این صورت معمول است:
const state$ = new BehaviorSubject({ user: null, settings: {}, isLoading: false });در سیگنال ها، اشیاء واکنشی عمیق تو در تو نامناسب هستند. شما نمی توانید بگویید user().settings().theme() - این یک خواندن در یک خواندن در یک خواندن است. در عوض، شما می خواهید مسطح کنید:
const user = signal<User | null>(null); const settings = signal<Settings>({});نکته: هر قسمت از حالت را با سیگنال خاص خود مدل کنید. انعطاف پذیری و کنترل واکنش پذیری آسان تر را به دست خواهید آورد.
سناریوی عملی: سفارشی سازی برچسب فرم
فرض کنید یک SearchSidebarComponent دارید و میخواهید برچسبهای آن را از والدین شخصیسازی کنید. این راه ساده لوحانه است:
labels = input<MapSidebarLabels | undefined>(undefined); What happens if you try to derive a computed value? labelsFinal = computed(() => { const raw = this.labels(); return { ...raw, title: raw.title.toUpperCase() }; });حالا فرض کنید در والد بنویسید:
<search-sidebar [labels]="labelsFinal()" /> این کار می کند، اما شما در حال فراخوانی یک سیگنال در یک سیگنال هستید. و اگر الگوی خود را به <search-sidebar [labels]="labelsFinal" /> تغییر دهید، با عدم تطابق نوع خراب می شود.
نکته: سیستم ورودی Angular هنوز کاملاً سیگنال بومی نیست. تا زمانی که باشد، قبل از ارسال ورودی، مقدار را صاف کنید .
Gotcha #3: effect() بلافاصله اجرا می شود - و شاید دوباره
بر خلاف RxJS subscribe() که فقط زمانی فعال میشود که چیزی منتشر میشود، effect() یک بار بر روی ایجاد فعال میشود، حتی اگر سیگنال هنوز تغییر نکرده باشد.
effect(() => { console.log("API call for", userId()); });این بلافاصله یک بار اجرا می شود، حتی اگر شناسه کاربری هنوز تغییر نکرده باشد. هنگام قرار دادن عوارض جانبی مانند تماسهای HTTP یا ردیابی تجزیه و تحلیل درون افکت () مراقب باشید.
نکته: منطق اثر نگهبانی () با چک های پوچ یا بازگشت زودهنگام در صورت نیاز.
افکار نهایی
سیگنال ها در Angular فقط یک نحو جدید نیستند، بلکه یک تغییر در مدل ذهنی هستند. هنگامی که فکر کردن در موارد مشاهدهپذیر را متوقف کنید و شروع به فکر کردن در متغیرهایی کنید که واکنش نشان میدهند، متوجه خواهید شد که اجزای شما کوچکتر، سریعتر و سادهتر هستند.
اما مانند هر ابزار جدید، سیگنال ها دارای لبه های تیز هستند. معاوضه ها را بشناسید، الگوها را بیاموزید، و مهمتر از همه، با سیگنال ها مانند دریافت کنندگان شیک رفتار نکنید . آنها بسیار قدرتمندتر از این هستند، اما به شرطی که مدل را درک کنید.
خبرکاو





ارسال نظر