FutureBuilder — ما هو، العمل مع Future في Flutter

المؤلف: IT Sectr نُشر: 2026-07-02 وقت القراءة: 8 دق

FutureBuilder هو عنصر واجهة في Flutter يعيد بناء واجهته تلقائياً بناءً على الحالة الحالية لـ AsyncSnapshot المستلمة من Future المُمرَّر. على عكس الاستدعاء اليدوي لـ setState بعد await، يوفر FutureBuilder نهجاً تصريحياً: فهو يشترك في Future عند أول عرض ويستدعي دالة builder عند كل تغيير في الحالة — تحميل، خطأ أو بيانات جاهزة. وفقاً لمرجع Flutter API (2026)، FutureBuilder مفيد بشكل خاص لتحميل البيانات من الشبكة، القراءة من قاعدة البيانات وأي عمليات غير متزامنة حيث يجب أن تعرض واجهة المستخدم مؤشر تحميل أو رسالة خطأ أو محتوى جاهز.

النقاط الرئيسية

  • FutureBuilder — عنصر واجهة Flutter لبناء واجهة المستخدم بناءً على حالة Future عبر AsyncSnapshot (none, waiting, active, done)
  • AsyncSnapshot — كائن يحتوي على الحالة الحالية للعملية غير المتزامنة: connectionState و data و error
  • builder — دالة استدعاء تُستدعى عند كل تغيير في حالة Future لإعادة بناء واجهة المستخدم
  • معالجة الأخطاء — AsyncSnapshot.hasError يسمح بعرض واجهة بديلة عند فشل العملية غير المتزامنة
  • ConnectionState — تعداد بأربع قيم: none (لا توجد عملية)، waiting (انتظار)، active (تدفق)، done (مكتمل)

ما هو FutureBuilder في Flutter

FutureBuilder هو عنصر واجهة مدمج في Flutter من حزمة widgets يأخذ Future ودالة builder. عندما تتغير حالة Future (قيد التشغيل، مكتمل مع بيانات، مكتمل مع خطأ)، يقوم FutureBuilder تلقائياً بإعادة بناء واجهة المستخدم باستدعاء builder مع AsyncSnapshot جديد. هذا يلغي الحاجة لإدارة حالة التحميل يدوياً عبر setState والأعلام.

على عكس StreamBuilder الذي يعمل مع تدفقات البيانات (Stream)، FutureBuilder مصمم للعمليات غير المتزامنة لمرة واحدة: طلب HTTP، قراءة ملف، استعلام قاعدة بيانات. FutureBuilder يدير الاشتراك في Future بنفسه: عند البناء الأول، يبدأ Future ويتتبع اكتماله. عندما يتم تدمير العنصر، لا يلغي FutureBuilder الـ Future — هذه مسؤولية المطور.

وفقاً لـ Flutter Cookbook (2026)، يُوصى باستخدام FutureBuilder للحالات التي تُنفذ فيها عملية غير متزامنة مرة واحدة عند تهيئة الشاشة. للعمليات المتكررة أو تدفقات البيانات، استخدم StreamBuilder. كلا العنصرين يتبعان نفس نمط واجهة المستخدم التفاعلية، لكن FutureBuilder محسّن للطلبات لمرة واحدة.

كيف يعمل FutureBuilder داخلياً

التنفيذ الداخلي لـ FutureBuilder يشترك في Future باستخدام Future.then و catchError. عند بدء FutureBuilder، يضبط connectionState على ConnectionState.waiting ويستدعي builder ببيانات فارغة. عند الاكتمال بنجاح، يتغير connectionState إلى ConnectionState.done مع البيانات. عند الخطأ، يمتلئ snapshot.error بكائن الخطأ. كل تغيير يؤدي إلى إعادة بناء العنصر.

AsyncSnapshot: الحالات والخصائص

AsyncSnapshot هو كائن حاوية يمرره FutureBuilder إلى دالة builder عند كل تغيير حالة. يحتوي على كل المعلومات حول الحالة الحالية للعملية غير المتزامنة: هل التحميل قيد التقدم، ما البيانات المستلمة، أو هل حدث خطأ. فهم AsyncSnapshot هو مفتاح بناء واجهة المستخدم بشكل صحيح مع FutureBuilder.

الخاصيةالنوعالوصف
connectionStateConnectionStateحالة الاتصال الحالية (none, waiting, active, done)
dataT?البيانات المستلمة من Future (null حتى الاكتمال أو عند الخطأ)
errorObject?كائن الخطأ إذا اكتمل Future باستثناء
hasDatabooltrue إذا كانت data ليست null و connectionState هي ConnectionState.done
hasErrorbooltrue إذا اكتمل Future بخطأ

ConnectionState: أربع حالات لعملية غير متزامنة

التعداد ConnectionState يحدد مرحلة العملية غير المتزامنة. None — الحالة الأولية عندما لم يبدأ Future بعد (نادر الاستخدام، عادة في البناء الأول بدون initialData). Waiting — Future قيد التنفيذ، البيانات لم تستلم بعد. Active — يُستخدم فقط بواسطة StreamBuilder للتدفقات ذات البيانات الجزئية. Done — اكتمل Future، البيانات متاحة عبر snapshot.data أو الخطأ عبر snapshot.error.

المعالجة الصحيحة لجميع حالات AsyncSnapshot في دالة builder هي شرط إلزامي لكود الإنتاج. إذا لم يتم معالجة حالة waiting، سيرى المستخدم شاشة فارغة أثناء التحميل. إذا لم يتم معالجة hasError، سيتلقى المستخدم استثناءً بدون شرح. النمط الموصى به: تحقق من hasError → تحقق من hasData → عرض التحميل افتراضياً.

أنماط استخدام FutureBuilder

FutureBuilder يمكن استخدامه بعدة أنماط قياسية، كل منها يحل مهمة محددة. دعنا ننظر إلى السيناريوهات الرئيسية: تحميل البيانات عند التهيئة، التحميل مع التخزين المؤقت، الطلبات المتوازية ومعالجة الأخطاء مع إعادة المحاولة.

تحميل البيانات عند تهيئة الشاشة

النمط الأكثر شيوعاً — FutureBuilder في دالة build لـ StatefulWidget أو StatelessWidget. يتم تمرير Future من initState أو إنشاؤه مباشرة في build. من المهم عدم إنشاء Future في دالة build عند كل إعادة بناء — سيؤدي ذلك إلى طلبات متكررة. استخدم Future مخزناً في حقل State.

التحميل مع التخزين المؤقت والتحديث

لمنع الطلبات المتكررة، يمكن دمج FutureBuilder مع CachedNetworkImage أو ذاكرة تخزين مؤقت محلية. بعد التحميل الأول، تُحفظ البيانات في الذاكرة أو SharedPreferences، ويعرض FutureBuilder البيانات المخزنة مؤقتاً فورياً مع تحديثها من الشبكة بالتوازي. هذا يحسن تجربة المستخدم من خلال الاستجابة الفورية.

وفقاً لـ pub.dev (2026)، التخزين المؤقت مهم بشكل خاص للصور وقوائم البيانات. FutureBuilder مع CachedNetworkImageProvider يعرض تلقائياً الصورة المخزنة مؤقتاً، وعند غيابها — مؤشر تحميل يليه عرض الملف الذي تم تنزيله.

FutureBuilder مقابل setState: أيهما تختار

FutureBuilder وإدارة الحالة اليدوية عبر setState هما نهجان لواجهة المستخدم غير المتزامنة في Flutter. لكل منهما مزاياه وقيوده. يعتمد الاختيار على تعقيد الشاشة وعدد العمليات غير المتزامنة.

FutureBuilder يتفوق في البساطة: لا تحتاج لإعلان حقول لحالة التحميل والبيانات والخطأ — كل شيء يُدار عبر AsyncSnapshot. إنه مثالي للشاشات البسيطة بعملية غير متزامنة واحدة (طلب HTTP واحد، قراءة قاعدة بيانات). ومع ذلك، مع 5+ عمليات غير متزامنة على شاشة واحدة، يُنشئ FutureBuilder تداخلاً مفرطاً — مما ينتج “هرماً” من FutureBuilders المتداخلة.

setState مع أعلام الحالة اليدوية يعطي تحكماً أكبر وقابلية قراءة أفضل للوغاريتمات المعقدة. للشاشات ذات الطلبات المتعددة والمترابطة (تحميل مستخدم → تحميل طلباته → تحميل تفاصيل الطلب)، من الأفضل استخدام setState مع ChangeNotifier أو Bloc. وفقاً لدليل إدارة حالة Flutter (2026)، للسيناريوهات المعقدة يُوصى باستخدام Riverpod أو Bloc بدلاً من FutureBuilder، حيث أنها توفر فصلاً أفضل بين المنطق والعرض.

مثال FutureBuilder مع تحميل بيانات من الشبكة

لنفكر في مثال عملي لـ FutureBuilder لتحميل قائمة مستخدمين من REST API. يوضح الكود المعالجة الصحيحة لحالات AsyncSnapshot الثلاث: التحميل والخطأ والبيانات الجاهزة.

dart
class UserListPage extends StatefulWidget {
  const UserListPage({super.key});

  @override
  State<UserListPage> createState() => _UserListPageState();
}

class _UserListPageState extends State<UserListPage> {
  final Future<List<User>> usersFuture = UserRepository().fetchUsers();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('المستخدمين')),
      body: FutureBuilder<List<User>>(
        future: usersFuture,
        builder: (context, AsyncSnapshot<List<User>> snapshot) {
          if (snapshot.hasError) {
            return Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  const Icon(Icons.error_outline, size: 48, color: Colors.red),
                  const SizedBox(height: 16),
                  Text('خطأ: ${snapshot.error}'),
                ],
              ),
            );
          }

          if (snapshot.hasData) {
            final users = snapshot.data!;
            return ListView.builder(
              itemCount: users.length,
              itemBuilder: (context, index) {
                return ListTile(
                  leading: CircleAvatar(backgroundImage: NetworkImage(users[index].avatarUrl)),
                  title: Text(users[index].name),
                  subtitle: Text(users[index].email),
                );
              },
            );
          }

          return const Center(child: CircularProgressIndicator());
        },
      ),
    );
  }
}

في المثال، FutureBuilder يعالج الحالات الثلاث. عند الخطأ، يتم عرض أيقونة مع رسالة خطأ. عند التحميل الناجح — ListView مع الصور الرمزية والأسماء. أثناء التحميل — CircularProgressIndicator. يُعلن Future كحقل فئة، مما يمنع الاستدعاء المتكرر عند إعادة البناء. هذا النمط يغطي 90% من سيناريوهات استخدام FutureBuilder في تطبيقات الجوال.

الأسئلة الشائعة

لماذا يستدعي FutureBuilder دالة builder عدة مرات؟

FutureBuilder يستدعي builder عند كل تغيير في حالة Future: المرة الأولى عند الإنشاء (connectionState: none أو waiting)، والمرة الثانية عند الاكتمال (connectionState: done). إذا أعيد بناء العنصر الأب، فسيتم إعادة بناء FutureBuilder أيضاً. لمنع الاستدعاءات المتكررة، تأكد من إنشاء Future خارج دالة build — وإلا فإن كل استدعاء لـ build سيُنشئ Future جديد.

كيف أمنع طلباً متكرراً عند إعادة البناء؟

خزّن Future في حقل StatefulWidget (في initState) أو استخدم التخزين المؤقت للاستدعاءات. إذا تم إنشاء Future داخل دالة build، فكل استدعاء لـ build سيُنشئ Future جديداً، وسيعيد FutureBuilder تشغيل العملية غير المتزامنة. لـ StatelessWidget، استخدم حزمة cached_future أو عناصر keep-alive بحيث يتم تنفيذ Future مرة واحدة بغض النظر عن إعادة البناء.

ما الفرق بين FutureBuilder و StreamBuilder؟

FutureBuilder مصمم للعمليات غير المتزامنة لمرة واحدة (طلب HTTP واحد، قراءة قاعدة بيانات واحدة). StreamBuilder يعمل مع تدفقات البيانات التي يمكنها إصدار قيم متعددة بمرور الوقت (دردشة، تحديثات الأسعار، تحديد الموقع الجغرافي). StreamBuilder يدعم ConnectionState.active للبيانات الجزئية، بينما FutureBuilder يدعم فقط waiting و done.

كيف أستخدم FutureBuilder مع Futures متعددة؟

لعدة Futures متوازية، استخدم Future.wait ومرر النتيجة إلى FutureBuilder واحد. Future.wait يأخذ قائمة من Futures ويعيد Future — عندما تكتمل جميع Futures، يتلقى builder مصفوفة من النتائج. للطلبات المتسلسلة، استخدم سلسلة Future.then داخل Future واحد أو FutureBuilders متداخلة (أقل قابلية للقراءة). البديل هو حزمة riverpod مع AsyncValue لحالات غير متزامنة متعددة.

كيف ألغي Future عند الخروج من الشاشة؟

FutureBuilder لا يلغي Future تلقائياً. للإلغاء، استخدم CancelableOperation من حزمة async أو آلية مخصصة عبر علامة cancelled في State. ضع العلامة في dispose()، وتحقق منها بعد اكتمال Future قبل استدعاء setState. بديلاً، استخدم حزمة riverpod مع AutoDispose التي تلغي تلقائياً العمليات غير المتزامنة عند الخروج من الشاشة.

الخلاصة

  • FutureBuilder — عنصر واجهة Flutter لبناء واجهة مستخدم تصريحي بناءً على حالة Future عبر AsyncSnapshot (waiting, done, error)
  • AsyncSnapshot — حاوية مع connectionState و data و error؛ ضرورية للمعالجة الصحيحة لجميع حالات العملية غير المتزامنة
  • builder — استدعاء بثلاثة فروع: hasError (عرض الخطأ)، hasData (عرض البيانات)، default (مؤشر التحميل)
  • FutureBuilder مقابل setState — FutureBuilder أبسط لعملية واحدة، setState مع Bloc/Riverpod أفضل للوغاريتمات المعقدة مع طلبات متعددة
  • منع الطلبات المتكررة — يجب أن يكون Future حقلاً في State، لا تنشئه في دالة build لتجنب إعادة التشغيل عند كل إعادة بناء
  • إلغاء Future — FutureBuilder لا يلغي Future عند dispose؛ استخدم CancelableOperation أو علامة إلغاء لمنع setState بعد التدمير
  • Futures متعددة — للطلبات المتوازية استخدم Future.wait مع FutureBuilder واحد؛ للمتسلسلة — سلاسل في Future واحد

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا