Element Tree: چیست، ارتباط با RenderObject و اصل کار

نویسنده: IT Sectr منتشر شده: 2026-07-01 زمان مطالعه: 10 دقیقه

Element Tree لایه‌ای میانی در Flutter است که Widget Tree اعلانی را به RenderObject Tree امری مرتبط می‌کند. برخلاف ویجت‌ها که در هر rebuild دوباره ساخته می‌شوند، عناصر بین به‌روزرسانی‌ها حفظ می‌شوند و حالت، کلیدها و چرخه حیات را مدیریت می‌کنند. طبق Flutter API Reference, 2025، درک Element Tree برای کار مؤثر با کلیدها، بهینه‌سازی عملکرد و اشکال‌زدایی رفتار غیرمنتظره ویجت‌ها ضروری است.

نکات اصلی

  • Element Tree لایه‌ای پایدار بین درخت‌های Widget و RenderObject است که بین بازسازی‌ها حفظ می‌شود.
  • هر ویجت عنصری ایجاد می‌کند که جاسازی آن در درخت و چرخه حیاتش را مدیریت می‌کند.
  • StatefulElement شیء State را نگه می‌دارد که حتی پس از بازسازی ویجت در دسترس باقی می‌ماند.
  • کلیدها (Key) در سطح Element Tree کار می‌کنند و به تطبیق ویجت‌ها هنگام بازسازی کمک می‌کنند.
  • Element Tree مستقیماً به RenderObject Tree مرتبط است — هر عنصر می‌تواند RenderObject ایجاد یا حذف کند.

Element Tree در Flutter چیست؟

Element Tree سلسله‌مراتب میانی در Flutter است که بر اساس Widget Tree ساخته می‌شود و جاسازی ویجت‌ها در اپلیکیشن را مدیریت می‌کند. هر نمونه عنصر با یک ویجت در درخت مطابقت دارد و ارجاعی به آن نگه می‌دارد. تفاوت اصلی عنصر با ویجت این است که عنصر موقعیت خود را در درخت بین بازسازی‌ها حفظ می‌کند، در حالی که ویجت ممکن است در هر فراخوانی build دوباره ساخته شود.

چرا Element Tree لازم است

بدون Element Tree، Flutter نمی‌توانست رابط را به‌طور مؤثر به‌روزرسانی کند. اگر هر rebuild درخت RenderObject Tree را دوباره می‌ساخت، عملکرد به‌طور غیرقابل قبولی پایین می‌بود. Element Tree نقش تثبیت‌کننده را ایفا می‌کند: ارجاع‌ها به RenderObject و State را بین به‌روزرسانی‌ها حفظ می‌کند و به Flutter امکان می‌دهد فقط حداقل تغییرات را به درخت رندر اعمال کند.

انواع عناصر

Flutter از سه نوع اصلی عنصر استفاده می‌کند: StatelessElement برای StatelessWidget، StatefulElement برای StatefulWidget و LeafRenderObjectElement، SingleChildRenderObjectElement، MultiChildRenderObjectElement برای RenderObjectWidget. هر نوع برای کلاس ویجت خود تخصصی است و تعیین می‌کند که عنصر چگونه با RenderObject تعامل دارد.

ارتباط Widget، Element و RenderObject در معماری سه لایه

معماری سه لایه Flutter از Widget Tree (پیکربندی)، Element Tree (مدیریت) و RenderObject Tree (رندر) تشکیل شده است. Element Tree حلقه اتصال است: پیکربندی را از Widget می‌خواند و دستورها را به RenderObject منتقل می‌کند. بدون Element Tree، فریمورک نمی‌توانست توصیف اعلانی را با رندر واقعی به‌طور مؤثر همگام‌سازی کند.

چگونه عنصر ویجت و RenderObject را به هم مرتبط می‌کند

وقتی عنصر در درخت جاسازی می‌شود، نوع ویجت را بررسی می‌کند. اگر ویجت RenderObjectWidget باشد، عنصر RenderObject مربوطه را ایجاد کرده و به RenderObject Tree اضافه می‌کند. اگر ویجت LeafRenderObjectWidget باشد، عنصر یک RenderObject برگ‌مانند ایجاد می‌کند. برای StatelessWidget و StatefulWidget، عنصر فقط جاسازی عناصر فرزند را مدیریت می‌کند.

dart
abstract class Element {
  Widget widget;
  Element? parent;
  List<Element>? children;

  void mount(Element? parent, dynamic newSlot);
  void update(Widget newWidget);
  void unmount();
}

این کد ساده‌شده ساختار پایه Element را نشان می‌دهد. هر عنصر ارجاعی به ویجت فعلی، عنصر والد و عناصر فرزند نگه می‌دارد. متدهای mount و update چرخه حیات عنصر و RenderObject مرتبط با آن را مدیریت می‌کنند.

چرخه حیات عنصر: از ایجاد تا حذف

هر عنصر در Flutter از دنباله‌ای از مراحل چرخه حیات عبور می‌کند: ایجاد، نصب، به‌روزرسانی و جدا کردن. درک این مراحل برای اشکال‌زدایی رفتار غیرمنتظره، به‌ویژه هنگام کار با انیمیشن‌ها، عملیات ناهمگام و مدیریت حالت ضروری است.

مرحله ۱: ایجاد عنصر

عنصر با فراخوانی متد createElement ویجت ایجاد می‌شود. برای StatelessWidget، StatelessElement و برای StatefulWidget، StatefulElement ساخته می‌شود (که شیء State را نیز ایجاد می‌کند). برای RenderObjectWidget، RenderObjectElement مربوطه ساخته می‌شود. ایجاد عنصر در اولین ظاهر شدن ویجت در Widget Tree رخ می‌دهد.

مرحله ۲: نصب (mount)

هنگام نصب، عنصر به Element Tree اضافه شده و عنصر والد را دریافت می‌کند. برای RenderObjectElement، نصب همچنین RenderObject را ایجاد کرده و آن را در RenderObject Tree جاسازی می‌کند. اگر ویجت StatefulWidget باشد، در این مرحله متد initState شیء State فراخوانی می‌شود.

مرحله ۳: به‌روزرسانی (update)

وقتی ویجت با پیکربندی جدید بازسازی می‌شود، عنصر از طریق متد update ویجت جدید را دریافت می‌کند. عنصر نوع ویجت جدید و قدیمی را مقایسه می‌کند: اگر انواع یکسان باشند، عنصر پیکربندی خود را به‌روزرسانی می‌کند؛ در غیر این صورت عنصر جدا شده و عنصر جدیدی ایجاد می‌شود. به این حالت «تغییر ویجت» گفته می‌شود و دلیل از دست رفتن حالت هنگام تغییر نوع است.

مرحله ۴: جدا کردن (unmount)

هنگام حذف ویجت از Widget Tree، متد unmount بر روی عنصر فراخوانی می‌شود. عنصر از Element Tree حذف می‌شود، RenderObject از RenderObject Tree حذف می‌شود و برای StatefulWidget متد dispose شیء State فراخوانی می‌شود. پس از unmount، اگر ویجت دوباره در همان موقعیت ظاهر شود، عنصر می‌تواند دوباره استفاده شود.

نقش کلیدها در Element Tree

کلیدها (Key) مکانیزم شناسایی عناصر هستند که به Flutter اجازه می‌دهند ویجت‌های Widget Tree قدیمی و جدید را نه بر اساس موقعیت، بلکه بر اساس شناسه یکتا مطابقت دهد. کلیدها هنگام کار با لیست‌های پویا که ترتیب عناصر می‌تواند تغییر کند حیاتی هستند: افزودن، حذف یا جابه‌جایی عناصر.

کلیدها چگونه بر Element Tree تأثیر می‌گذارند

بدون کلید، Flutter عناصر را بر اساس موقعیت آنها در درخت مطابقت می‌دهد: عنصر در موقعیت ۰ درخت قدیمی با ویجت در موقعیت ۰ درخت جدید جایگزین می‌شود. اگر ترتیب تغییر کرده باشد، عناصر به هم می‌ریزند و حالت ممکن است از بین برود یا به داده‌های اشتباه متصل شود. کلید Flutter را مجبور می‌کند عنصر را بر اساس شناسه جستجو کند، نه بر اساس موقعیت.

ValueKey، ObjectKey و UniqueKey

ValueKey برای شناسایی عنصر از یک مقدار ساده (رشته، عدد) استفاده می‌کند. ObjectKey از ارجاع به یک شیء استفاده می‌کند — زمانی مناسب است که عنصر شناسه رشته‌ای پایداری ندارد. UniqueKey در هر ایجاد یک شناسه یکتا تولید می‌کند — زمانی استفاده می‌شود که هر نمونه ویجت باید یکتا باشد.

dart
Column(
  children: items.map((item) => TodoItem(
    key: ValueKey(item.id),
    title: item.title,
    isDone: item.isDone,
  )).toList(),
)

در این مثال، ValueKey با item.id تضمین می‌کند که هر TodoItem حالت خود را (مثلاً فوکوس فیلد ورودی) هنگام تغییر ترتیب عناصر در لیست حفظ کند. بدون کلید، عنصر در موقعیت اول حالت عنصر قبلی در همان موقعیت را دریافت می‌کرد.

Element Tree چگونه حالت را مدیریت می‌کند

حالت (State) در Flutter نه در ویجت‌ها، بلکه در عناصر ذخیره می‌شود. وقتی StatefulWidget بازسازی شده و نمونه جدیدی از ویجت ایجاد می‌کند، StatefulElement مربوطه ارجاع به شیء State قدیمی را حفظ می‌کند. ویجت جدید به State موجود متصل می‌شود و این امکان حفظ داده‌ها بین بازسازی‌ها را فراهم می‌کند.

چرا حالت هنگام rebuild از بین نمی‌رود

هنگام بازسازی ویجت، Flutter نمونه جدیدی از StatefulWidget ایجاد می‌کند، اما StatefulElement مربوطه در Element Tree باقی می‌ماند. عنصر متد update را در State فراخوانی کرده و ویجت جدید را منتقل می‌کند. به این ترتیب شیء State و داده‌هایش حفظ می‌شوند. از دست رفتن حالت فقط هنگام تغییر نوع ویجت، تغییر کلید یا حذف عنصر از درخت رخ می‌دهد.

InheritedWidget و Element Tree

InheritedElement عنصر ویژه‌ای است که به عناصر فرزند اجازه می‌دهد بدون انتقال صریح از طریق سازنده‌ها، داده‌ها را از InheritedWidget والد دریافت کنند. وقتی InheritedWidget تغییر می‌کند، InheritedElement همه عناصر وابسته را مطلع می‌کند و آنها بازسازی می‌شوند. این مکانیزم اساس Theme، MediaQuery و Provider است.

  • وابستگی — هنگام فراخوانی dependOnInheritedWidgetOfExactType، عنصر به‌عنوان وابسته به InheritedElement ثبت می‌شود.
  • اطلاع‌رسانی — هنگام تغییر InheritedWidget، فریمورک همه عناصر وابسته را به‌عنوان نیازمند بازسازی علامت‌گذاری می‌کند.
  • بازسازی — عناصر وابسته در فریم بعدی بازسازی شده و رابط را مطابق داده‌های جدید به‌روزرسانی می‌کنند.

تأثیر Element Tree بر عملکرد

Element Tree حافظه مصرف می‌کند و بر سرعت رندر اول تأثیر می‌گذارد. هر عنصر مقدار مشخصی حافظه اشغال می‌کند: ارجاع به ویجت، ارجاع به والد، فهرست عناصر فرزند، اسلات و فیلدهای اضافی برای RenderObjectElement. بهینه‌سازی Element Tree زمان راه‌اندازی را کاهش داده و مصرف حافظه را کم می‌کند.

استفاده مجدد از عناصر

Flutter هنگام بازسازی سعی می‌کند عناصر را دوباره استفاده کند. اگر ویجت در پیکربندی جدید نوع و کلید یکسانی داشته باشد، عنصر دوباره ساخته نمی‌شود — به‌روزرسانی می‌شود. این بسیار سریع‌تر از ایجاد عنصر جدید و نصب آن است. اما هنگام تغییر نوع یا کلید، عنصر قدیمی جدا می‌شود و عنصر جدید از صفر ساخته می‌شود.

RepaintBoundary و Element Tree

RepaintBoundary یک RenderRepaintBoundary جداگانه در RenderObject Tree ایجاد می‌کند که بخشی از درخت را ایزوله می‌کند. در سطح Element Tree، RepaintBoundary عنصر ویژه‌ای ایجاد نمی‌کند — از SingleChildRenderObjectElement استفاده می‌کند. تفاوت در سطح RenderObject نمایان می‌شود: هنگام تغییر محتوا، فقط ناحیه ایزوله‌شده RepaintBoundary دوباره رنگ می‌شود.

عملیاتبدون RepaintBoundaryبا RepaintBoundary
رنگ‌آمیزی مجددکل صفحهفقط ناحیه ایزوله‌شده
زمان~۱۶ میلی‌ثانیه در ۶۰ FPS~۲ تا ۵ میلی‌ثانیه
حافظهحداقل+ چند کیلوبایت برای هر لایه

همانطور که جدول نشان می‌دهد، RepaintBoundary با ایزوله کردن ناحیه متغیر، زمان رنگ‌آمیزی مجدد را به‌طور قابل توجهی کاهش می‌دهد. در سطح Element Tree این نیاز به پیکربندی اضافی ندارد — کافی است ویجت متغیر را در RepaintBoundary بپیچید.

سؤالات متداول

تفاوت بین Widget Tree و Element Tree چیست؟

Widget Tree پیکربندی است که در هر rebuild دوباره ساخته می‌شود. Element Tree ساختار پایداری است که بین به‌روزرسانی‌ها حفظ می‌شود و حالت، RenderObject و چرخه حیات ویجت‌ها را مدیریت می‌کند.

چرا Element Tree برای عملکرد مهم است؟

بدون Element Tree، Flutter مجبور بود در هر تغییر حالت، RenderObject Tree را دوباره بسازد که باعث تأخیرهای قابل توجه می‌شد. Element Tree با حفظ RenderObject و State امکان اعمال فقط حداقل تغییرات را فراهم می‌کند.

چه زمانی عنصر از Element Tree حذف می‌شود؟

عنصر زمانی حذف می‌شود که ویجت مربوطه از Widget Tree ناپدید شود، یا زمانی که نوع ویجت (مثلاً جایگزینی Column با Row) یا کلید تغییر کند. هنگام جدا شدن، dispose در State فراخوانی می‌شود.

کلیدها چگونه بر Element Tree تأثیر می‌گذارند؟

کلیدها الگوریتم تطبیق را تغییر می‌دهند: Flutter به جای جستجوی عنصر بر اساس موقعیت، آن را بر اساس مقدار کلید جستجو می‌کند. این امکان حفظ حالت هنگام تغییر ترتیب یا تعداد ویجت‌ها را فراهم می‌کند.

آیا می‌توان به Element Tree به‌طور مستقیم دسترسی داشت؟

بله، از طریق BuildContext که انتزاعی از عنصر است. متدهای findAncestorWidgetOfExactType و dependOnInheritedWidgetOfExactType با بالا رفتن در درخت عناصر روی Element Tree کار می‌کنند.

خلاصه

  • Element Tree لایه میانی پایداری بین درخت‌های Widget و RenderObject است که حالت را بین بازسازی‌ها حفظ می‌کند.
  • هر ویجت بسته به نوع خود عنصری ایجاد می‌کند: StatelessElement، StatefulElement یا RenderObjectElement.
  • چرخه حیات عنصر شامل ایجاد، نصب، به‌روزرسانی و جدا کردن است — درک این مراحل برای اشکال‌زدایی ضروری است.
  • کلیدها (Key) در سطح Element Tree کار می‌کنند و تطبیق صحیح ویجت‌ها را هنگام تغییرات پویا تضمین می‌کنند.
  • StatefulElement شیء State را نگه می‌دارد که در صورت عدم تغییر نوع و کلید، هنگام بازسازی ویجت حفظ می‌شود.
  • InheritedElement عناصر وابسته را از تغییرات مطلع می‌کند و انتقال واکنشی داده‌ها به پایین درخت را تضمین می‌کند.
  • معماری سه لایه Widget ← Element ← RenderObject به Flutter اجازه می‌دهد رابط را به‌طور مؤثر به‌روزرسانی کند و عملیات رندر پرهزینه را به حداقل برساند.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید