نوفيل
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
دخولابدأ مجاناً
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
نوفيل

منصة تعليم البرمجة الأولى بالعربي. تعلم من الصفر حتى الاحتراف مع كورسات احترافية وتحديات ذكاء اصطناعي.

المنصة

  • الكورسات
  • التحديات
  • المقالات
  • الأدوات

الحساب

  • إنشاء حساب
  • تسجيل الدخول
  • لوحة التحكم
  • الملف الشخصي

روابط

  • سياسة الخصوصية
  • شروط الاستخدام
  • عن نوفيل
  • تواصل معنا

© 2026 نوفيل. جميع الحقوق محفوظة.

صُنع بـ في مصر

نوفيل
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
دخولابدأ مجاناً
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
نوفيل

منصة تعليم البرمجة الأولى بالعربي. تعلم من الصفر حتى الاحتراف مع كورسات احترافية وتحديات ذكاء اصطناعي.

المنصة

  • الكورسات
  • التحديات
  • المقالات
  • الأدوات

الحساب

  • إنشاء حساب
  • تسجيل الدخول
  • لوحة التحكم
  • الملف الشخصي

روابط

  • سياسة الخصوصية
  • شروط الاستخدام
  • عن نوفيل
  • تواصل معنا

© 2026 نوفيل. جميع الحقوق محفوظة.

صُنع بـ في مصر

نوفيل
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
دخولابدأ مجاناً
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
نوفيل

منصة تعليم البرمجة الأولى بالعربي. تعلم من الصفر حتى الاحتراف مع كورسات احترافية وتحديات ذكاء اصطناعي.

المنصة

  • الكورسات
  • التحديات
  • المقالات
  • الأدوات

الحساب

  • إنشاء حساب
  • تسجيل الدخول
  • لوحة التحكم
  • الملف الشخصي

روابط

  • سياسة الخصوصية
  • شروط الاستخدام
  • عن نوفيل
  • تواصل معنا

© 2026 نوفيل. جميع الحقوق محفوظة.

صُنع بـ في مصر

نوفيل
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
دخولابدأ مجاناً
الرئيسيةالكورساتالتحديات⚔️ المبارزاتالمقالاتالأدواتتغريداتالمجتمع
المقالات/Angular
Angular

Angular Signals: هل هي حقاً ثورة في إدارة الحالة أم مجرد ضجيج جديد؟

تعرّف على Angular Signals من الداخل: كيف تعمل خلف الكواليس، متى تستخدمها بدلاً من RxJS، والأخطاء الشائعة التي يقع فيها حتى المطورون المحترفون. دليل عملي لفهم الثورة القادمة في إدارة الحالة داخل Angular.

فريق نوفيل١٩ أغسطس ٢٠٢٦9 دقائق قراءة١٠ مشاهدة

قبل عامين، كنت أعمل على تطبيق مصرفي ضخم مبني بـ Angular. المشكلة؟ كل مرة نغير قيمة في الـ state، كان التطبيق يعيد رسم مكونات كاملة دون داعٍ، حتى تلك التي لا تعتمد على هذه القيمة. النتيجة؟ الـ UI يتجمد لثوانٍ، والمستخدمون يشكون من بطء غير مفهوم. حينها قلت لنفسي: «يبدو أن Angular بحاجة لشيء جديد». هذا الشيء كان Angular Signals، الذي ظهر في الإصدار 16 كخطوة أولى نحو تغيير جذري في كيفية إدارة الحالة داخل الإطار. لكن هل هي حقاً ثورة كما يدعي البعض، أم مجرد إضافة أخرى ستُنسى بعد عام؟

الحقيقة هي أن Angular Signals ليست مجرد ميزة جديدة، بل إعادة تفكير كاملة في كيفية تتبع التبعيات بين المكونات والبيانات. في عالم الـ JavaScript الحديث، حيث أصبحت التطبيقات أكثر تعقيداً من أي وقت مضى، أصبحت إدارة الحالة أمراً بالغ الأهمية. لكن المشكلة الأكبر ليست في كيفية تغيير الحالة، بل في كيفية معرفة متى يجب تحديث واجهة المستخدم بناءً على هذه التغييرات. هنا يأتي دور الـ Signals، التي تقدم نموذجاً جديداً يعتمد على مفهوم «التتبع الدقيق للتبعيات» بدلاً من الـ Change Detection التقليدي الذي يعتمد على الـ Zone.js.

ما هي Angular Signals بالضبط؟ ولماذا ظهرت الآن؟

لفهم Angular Signals، يجب أولاً فهم المشكلة التي تحاول حلها. في Angular التقليدي، يعتمد الإطار على Zone.js لالتقاط التغييرات في الحالة. الـ Zone.js هو مكتبة تقوم بـ monkey patching للعديد من وظائف الـ JavaScript الأصلية (مثل setTimeout، addEventListener، وغيرها) لتتبع متى تحدث تغييرات قد تؤثر على واجهة المستخدم. عندما يحدث تغيير، يقوم Angular بتشغيل دورة الـ Change Detection، التي تمر على جميع المكونات في الشجرة وتتحقق من التغييرات.

المشكلة هنا هي أن هذا النموذج «جشع» بطبيعته. حتى لو تغيرت قيمة واحدة صغيرة في جزء بعيد من التطبيق، قد ينتهي الأمر بإعادة رسم مكونات كاملة لا علاقة لها بهذه القيمة. هذا ليس فقط غير فعال من حيث الأداء، بل يجعل من الصعب التنبؤ بسلوك التطبيق، خاصة في التطبيقات الكبيرة والمعقدة. هنا تأتي Angular Signals بمفهوم جديد: «التتبع الدقيق للتبعيات». بدلاً من الاعتماد على Zone.js، تسمح الـ Signals لـ Angular بمعرفة بالضبط أي مكونات تعتمد على أي قيمة، وبالتالي تحديث فقط ما يحتاج إلى التحديث.

typescript
// مثال بسيط على Signal في Angular
import { signal } from '@angular/core';

@Component({
 selector: 'app-counter',
 template: `{{ count() }} <button (click)="increment()">زيادة</button>`
})
export class CounterComponent {
 // تعريف Signal مع القيمة الأولية
 count = signal(0);

 increment() {
 // تحديث قيمة Signal
 this.count.update(current => current + 1);
 }
}

// في القالب، نستخدم count() بدلاً من count مباشرة
// لأن الـ Signal هي دالة getter

في المثال أعلاه، عندما نستخدم `count()` في القالب، يخبر Angular تلقائياً أن هذا المكون يعتمد على الـ Signal المسمى `count`. عندما تتغير قيمة الـ Signal (من خلال `update` أو `set`)، يعرف Angular بالضبط أن هذا المكون فقط يحتاج إلى التحديث، وليس أي مكون آخر في التطبيق. هذا يختلف تماماً عن النموذج التقليدي، حيث كان Angular يعيد رسم جميع المكونات في الشجرة بدءاً من الجذر.

كيف تعمل Angular Signals خلف الكواليس؟

لفهم كيفية عمل Angular Signals، يجب الغوص قليلاً في التفاصيل التقنية لما يحدث خلف الكواليس. عندما تنشئ Signal باستخدام `signal(0)`، فإنك في الواقع تنشئ كائناً يحتوي على عدة خصائص داخلية. أهم هذه الخصائص هي:

  • •**القيمة الحالية**: تخزن القيمة الحالية للـ Signal.
  • •**الـ Subscribers**: قائمة بالمكونات أو التأثيرات التي تعتمد على هذه الـ Signal.
  • •**الـ Producer**: دالة مسؤولة عن حساب القيمة عندما تكون الـ Signal مشتقة من إشارات أخرى (مثل الـ computed Signals).
  • •**الـ Version**: رقم إصدار داخلي يتغير مع كل تحديث للـ Signal، مما يسمح لـ Angular بمعرفة متى يجب إعادة حساب القيم المشتقة.

عندما تقرأ قيمة الـ Signal باستخدام `count()`، يحدث أمران مهمان خلف الكواليس:

  1. يضيف Angular المكون الحالي (أو التأثير) إلى قائمة الـ Subscribers الخاصة بالـ Signal. هذا يعني أن المكون الآن «معتمد» على هذه الـ Signal.
  2. يخزن Angular رقم الإصدار الحالي للـ Signal داخل المكون. هذا الرقم مهم لأنه يسمح لـ Angular بمعرفة فيما بعد ما إذا كانت القيمة قد تغيرت أم لا دون الحاجة إلى مقارنة القيم الفعلية.

عندما تتغير قيمة الـ Signal (من خلال `set` أو `update`)، يحدث ما يلي:

  1. تحدث القيمة الداخلية للـ Signal.
  2. يزيد رقم الإصدار الداخلي للـ Signal.
  3. يخطر Angular جميع الـ Subscribers (المكونات أو التأثيرات) بأن القيمة قد تغيرت.
  4. لكل مشترك، يقارن Angular رقم الإصدار المخزن في المكون مع الرقم الجديد للـ Signal. إذا كانا مختلفين، يعلم Angular أن المكون يحتاج إلى التحديث.

هذا النموذج يختلف تماماً عن الـ Change Detection التقليدي، الذي كان يعتمد على مقارنة القيم الفعلية باستخدام `===`. في النموذج الجديد، لا يحتاج Angular إلى مقارنة القيم على الإطلاق، بل يعتمد فقط على رقم الإصدار، مما يجعل العملية أسرع بكثير وأكثر كفاءة.

typescript
// مثال على computed Signal مع تتبع التبعيات
import { signal, computed } from '@angular/core';

@Component({
 selector: 'app-user-profile',
 template: `
 <p>الاسم: {{ fullName() }}</p>
 <p>العمر: {{ age() }}</p>
 <p>العمر بعد 5 سنوات: {{ ageInFiveYears() }}</p>
 `
})
export class UserProfileComponent {
 firstName = signal('أحمد');
 lastName = signal('محمد');
 age = signal(30);

 // computed Signal يعتمد على إشارات أخرى
 fullName = computed(() => `${this.firstName()} ${this.lastName()}`);
 ageInFiveYears = computed(() => this.age() + 5);

 updateProfile() {
 this.firstName.set('خالد');
 this.age.update(a => a + 1);
 // فقط fullName و ageInFiveYears سيتأثران بالتغييرات، وليس المكون بأكمله
 }
}

في المثال أعلاه، عندما تتغير قيمة `firstName` أو `age`، يعرف Angular بالضبط أن `fullName` و `ageInFiveYears` فقط يحتاجان إلى إعادة الحساب، وليس أي جزء آخر من القالب. هذا النوع من التتبع الدقيق للتبعيات هو ما يجعل Angular Signals قوية للغاية، خاصة في التطبيقات الكبيرة حيث كانت إعادة رسم المكونات الكاملة تسبب مشاكل في الأداء.

متى يجب استخدام Angular Signals ومتى تبقى مع RxJS؟

هذا هو السؤال الذي يشغل بال الكثير من المطورين حالياً. هل يجب علينا التخلي عن RxJS بالكامل والانتقال إلى Signals؟ الإجابة القصيرة هي: لا. RxJS و Signals هما أداتان مختلفتان لحل مشاكل مختلفة، وكل منهما له مكانه في التطبيقات الحديثة. لفهم متى يجب استخدام كل منهما، دعونا نقارن بين النموذجين:

  • •**RxJS**: مناسب للتعامل مع تدفقات البيانات غير المتزامنة والمعقدة، مثل التعامل مع الـ HTTP requests، الـ WebSockets، أو الأحداث التي تحدث بشكل متكرر (مثل الـ mouse movements). RxJS يوفر أدوات قوية مثل `mergeMap`، `switchMap`، و `debounceTime` التي تجعل من السهل التعامل مع هذه السيناريوهات.
  • •**Signals**: مناسب لإدارة الحالة المتزامنة داخل التطبيق، خاصة عندما تريد تتبع تبعيات دقيقة بين المكونات والبيانات. الـ Signals تجعل من السهل معرفة بالضبط متى وأين يجب تحديث واجهة المستخدم دون الحاجة إلى إعادة رسم المكونات الكاملة.

في رأيي الشخصي، أفضل نهج هو استخدام كل أداة في مكانها المناسب. على سبيل المثال، يمكنك استخدام RxJS للتعامل مع الـ API calls، ثم تحويل الـ Observables إلى Signals باستخدام `toSignal` لعرض البيانات في واجهة المستخدم. هذا يجمع بين قوة RxJS في التعامل مع البيانات غير المتزامنة وسهولة الـ Signals في إدارة الحالة داخل المكونات.

typescript
// دمج RxJS مع Signals باستخدام toSignal
import { Component, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { toSignal } from '@angular/core/rxjs-interop';
import { signal } from '@angular/core';

@Component({
 selector: 'app-user-list',
 template: `
 <div *ngIf="users() as users">
 <ul>
 <li *ngFor="let user of users">{{ user.name }}</li>
 </ul>
 </div>
 <div *ngIf="loading()">جاري التحميل...</div>
 <div *ngIf="error() as error">{{ error }}</div>
 `
})
export class UserListComponent {
 private http = inject(HttpClient);
 
 // Signal للتحكم في حالة التحميل
 loading = signal(true);
 
 // تحويل Observable إلى Signal
 users = toSignal(this.http.get<User[]>('https://api.example.com/users'), {
 initialValue: [],
 });
 
 // Signal لعرض الأخطاء
 error = signal<string | null>(null);
 
 ngOnInit() {
 this.http.get<User[]>('https://api.example.com/users').subscribe({
 next: (users) => {
 this.users.set(users); // تحديث Signal بالقيم الجديدة
 this.loading.set(false);
 },
 error: (err) => {
 this.error.set('فشل تحميل البيانات');
 this.loading.set(false);
 }
 });
 }
}

interface User {
 id: number;
 name: string;
}

في هذا المثال، نستخدم RxJS للتعامل مع الـ HTTP request، ثم نحول الـ Observable إلى Signal باستخدام `toSignal`. هذا يسمح لنا بالاستفادة من قوة RxJS في التعامل مع البيانات غير المتزامنة، وفي نفس الوقت نستفيد من سهولة الـ Signals في إدارة الحالة داخل المكونات. لاحظ كيف استخدمنا `loading` و `error` كإشارات مستقلة للتحكم في حالة واجهة المستخدم، مما يجعل الكود أكثر وضوحاً وسهولة في الصيانة.

الأخطاء الشائعة وكيفية تجنبها عند استخدام Angular Signals

على الرغم من أن Angular Signals تبدو بسيطة في الاستخدام، إلا أن هناك العديد من الفخاخ التي يمكن أن يقع فيها حتى المطورون المحترفون. إليك بعض الأخطاء الشائعة وكيفية تجنبها:

1. استخدام Signals في الأماكن الخطأ

أحد الأخطاء الشائعة هو محاولة استخدام Signals في كل مكان، حتى في الحالات التي لا تكون فيها ضرورية. على سبيل المثال، إذا كان لديك مكون بسيط جداً لا يعتمد على أي حالة خارجية، فقد لا يكون هناك داعٍ لاستخدام Signals على الإطلاق. في هذه الحالات، قد يكون استخدام المتغيرات العادية أكثر كفاءة وأبسط في الفهم. تذكر أن الـ Signals تأتي مع بعض الـ Overhead، لذلك يجب استخدامها فقط عندما توفر قيمة حقيقية في الأداء أو الوضوح.

2. نسيان استخدام () عند قراءة قيمة Signal

هذا خطأ شائع جداً بين المطورين الجدد في استخدام Signals. عندما تريد قراءة قيمة Signal، يجب عليك استخدام `signalName()` بدلاً من `signalName` مباشرة. إذا نسيت الأقواس، فستحصل على الكائن Signal نفسه بدلاً من قيمته، مما قد يؤدي إلى أخطاء غريبة في واجهة المستخدم. على سبيل المثال:

typescript
// ❌ خطأ: نسيان الأقواس
<p>{{ count }}</p> // سيظهر [object Object] بدلاً من القيمة

// ✅ صحيح: استخدام الأقواس
<p>{{ count() }}</p> // سيظهر القيمة الفعلية

3. تعديل الـ Signals خارج الـ Zone.js

إذا قمت بتعديل قيمة Signal خارج سياق Zone.js (على سبيل المثال، داخل callback من مكتبة خارجية أو داخل Web Worker)، فقد لا يتم تحديث واجهة المستخدم كما هو متوقع. هذا لأن Angular يعتمد على Zone.js لالتقاط التغييرات في الحالة. لحل هذه المشكلة، يمكنك استخدام `NgZone.run` لتشغيل الكود داخل Zone.js:

typescript
import { NgZone } from '@angular/core';

constructor(private ngZone: NgZone) {}

someExternalCallback(newValue: number) {
 this.ngZone.run(() => {
 this.count.set(newValue); // سيتم تحديث واجهة المستخدم بشكل صحيح
 });
}

4. إنشاء دوائر تبعية في الـ computed Signals

من الأخطاء الخطيرة التي يمكن أن تقع فيها هو إنشاء دوائر تبعية في الـ computed Signals. على سبيل المثال، إذا كان لديك computed Signal يعتمد على نفسه بطريقة غير مباشرة، فقد ينتهي بك الأمر بدائرة لا نهائية تؤدي إلى تجميد التطبيق. Angular ستحاول اكتشاف هذه الدوائر وإلقاء خطأ، لكن من الأفضل تجنبها تماماً من البداية. إليك مثال على دائرة تبعية خطيرة:

typescript
// ❌ دائرة تبعية خطيرة
const a = signal(1);
const b = computed(() => a() + 1);
const c = computed(() => b() + 1);

// هذا سيؤدي إلى خطأ
const d = computed(() => c() + a()); // a يعتمد على c الذي يعتمد على b الذي يعتمد على a

مستقبل Angular Signals: ماذا نتوقع في الإصدارات القادمة؟

منذ ظهور Angular Signals في الإصدار 16، أصبح واضحاً أن فريق Angular يراهن بشكل كبير على هذه الميزة كمستقبل لإدارة الحالة داخل الإطار. في الإصدار 17، رأينا المزيد من التكامل بين Signals والنظام البيئي لـ Angular، مثل دعم الـ Signals في الـ Router و الـ Forms. لكن هذا مجرد بداية، وهناك العديد من الميزات المثيرة التي نتوقع رؤيتها في الإصدارات القادمة.

أحد أكثر الأمور إثارة هو التكامل الأعمق بين Signals و RxJS. حالياً، يمكنك تحويل الـ Observables إلى Signals باستخدام `toSignal`، لكننا نتوقع رؤية المزيد من الأدوات التي تجعل هذا التكامل أكثر سلاسة. على سبيل المثال، قد نرى دوال جديدة مثل `toObservable` لتحويل الـ Signals إلى Observables بسهولة، مما يسهل دمج الـ Signals مع المكتبات التي تعتمد على RxJS.

هناك أيضاً حديث عن دعم الـ Signals في الـ Angular Universal (الـ Server-Side Rendering). حالياً، الـ Signals تعمل بشكل جيد في بيئة المتصفح، لكن هناك بعض التحديات في بيئة الخادم، خاصة فيما يتعلق بالتزامن والحالة المشتركة بين الطلبات. نتوقع أن يرى فريق Angular حلولاً لهذه التحديات في الإصدارات القادمة، مما يجعل من الممكن استخدام الـ Signals في تطبيقات الـ SSR دون مشاكل.

أخيراً، هناك توقعات بأن نرى المزيد من الأدوات المساعدة لـ Signals في مكتبة Angular نفسها. على سبيل المثال، قد نرى دوال جديدة مثل `effect` لإدارة الآثار الجانبية بطريقة أكثر كفاءة، أو أدوات لتحسين أداء الـ computed Signals في الحالات المعقدة. مهما كانت الميزات الجديدة، من الواضح أن Angular Signals هنا لتبقى، وأنها ستشكل مستقبل إدارة الحالة في Angular لسنوات قادمة.


خلاصة المهندس: نصيحة من قلب التجربة

بعد أكثر من عام من العمل مع Angular Signals في مشاريع حقيقية، يمكنني القول بثقة: إذا كنت تعمل على تطبيق متوسط أو كبير الحجم، فابدأ في استخدام Signals اليوم. لا تنتظر حتى تصبح جزءاً من «الماضي». ابدأ بمكونات صغيرة، ثم قم بتوسيع استخدامها تدريجياً. لكن تذكر، لا تستخدم Signals في كل مكان فقط لأنها جديدة. استخدمها حيث توفر قيمة حقيقية في الأداء أو الوضوح، واترك RxJS للتعامل مع البيانات غير المتزامنة والمعقدة.

الخطوة العملية التالية؟ اختر مكوناً واحداً في تطبيقك الحالي، وحاول إعادة كتابته باستخدام Signals بدلاً من الـ Change Detection التقليدي. سترى الفرق بنفسك في الأداء والسلاسة. وعندما تفعل ذلك، لا تنسَ مراقبة الـ Memory Usage و الـ Change Detection Cycles باستخدام أدوات المطور في المتصفح. هذا هو أفضل طريقة لفهم كيف تغير Signals قواعد اللعبة حقاً.

Angular Signals إدارة الحالة RxJS أداء الويب تطوير واجهات المستخدم

التعليقات

العودة للمقالات
نوفيل

منصة تعليم البرمجة الأولى بالعربي. تعلم من الصفر حتى الاحتراف مع كورسات احترافية وتحديات ذكاء اصطناعي.

المنصة

  • الكورسات
  • التحديات
  • المقالات
  • الأدوات

الحساب

  • إنشاء حساب
  • تسجيل الدخول
  • لوحة التحكم
  • الملف الشخصي

روابط

  • سياسة الخصوصية
  • شروط الاستخدام
  • عن نوفيل
  • تواصل معنا

© 2026 نوفيل. جميع الحقوق محفوظة.

صُنع بـ في مصر