Element Tree لایهای میانی در Flutter است که Widget Tree اعلانی را به RenderObject Tree امری مرتبط میکند. برخلاف ویجتها که در هر rebuild دوباره ساخته میشوند، عناصر بین بهروزرسانیها حفظ میشوند و حالت، کلیدها و چرخه حیات را مدیریت میکنند. طبق Flutter API Reference, 2025، درک Element Tree برای کار مؤثر با کلیدها، بهینهسازی عملکرد و اشکالزدایی رفتار غیرمنتظره ویجتها ضروری است.
نکات اصلی
Element Tree سلسلهمراتب میانی در Flutter است که بر اساس Widget Tree ساخته میشود و جاسازی ویجتها در اپلیکیشن را مدیریت میکند. هر نمونه عنصر با یک ویجت در درخت مطابقت دارد و ارجاعی به آن نگه میدارد. تفاوت اصلی عنصر با ویجت این است که عنصر موقعیت خود را در درخت بین بازسازیها حفظ میکند، در حالی که ویجت ممکن است در هر فراخوانی build دوباره ساخته شود.
بدون Element Tree، Flutter نمیتوانست رابط را بهطور مؤثر بهروزرسانی کند. اگر هر rebuild درخت RenderObject Tree را دوباره میساخت، عملکرد بهطور غیرقابل قبولی پایین میبود. Element Tree نقش تثبیتکننده را ایفا میکند: ارجاعها به RenderObject و State را بین بهروزرسانیها حفظ میکند و به Flutter امکان میدهد فقط حداقل تغییرات را به درخت رندر اعمال کند.
Flutter از سه نوع اصلی عنصر استفاده میکند: StatelessElement برای StatelessWidget، StatefulElement برای StatefulWidget و LeafRenderObjectElement، SingleChildRenderObjectElement، MultiChildRenderObjectElement برای RenderObjectWidget. هر نوع برای کلاس ویجت خود تخصصی است و تعیین میکند که عنصر چگونه با RenderObject تعامل دارد.
معماری سه لایه Flutter از Widget Tree (پیکربندی)، Element Tree (مدیریت) و RenderObject Tree (رندر) تشکیل شده است. Element Tree حلقه اتصال است: پیکربندی را از Widget میخواند و دستورها را به RenderObject منتقل میکند. بدون Element Tree، فریمورک نمیتوانست توصیف اعلانی را با رندر واقعی بهطور مؤثر همگامسازی کند.
وقتی عنصر در درخت جاسازی میشود، نوع ویجت را بررسی میکند. اگر ویجت RenderObjectWidget باشد، عنصر RenderObject مربوطه را ایجاد کرده و به RenderObject Tree اضافه میکند. اگر ویجت LeafRenderObjectWidget باشد، عنصر یک RenderObject برگمانند ایجاد میکند. برای StatelessWidget و StatefulWidget، عنصر فقط جاسازی عناصر فرزند را مدیریت میکند.
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 رخ میدهد.
هنگام نصب، عنصر به Element Tree اضافه شده و عنصر والد را دریافت میکند. برای RenderObjectElement، نصب همچنین RenderObject را ایجاد کرده و آن را در RenderObject Tree جاسازی میکند. اگر ویجت StatefulWidget باشد، در این مرحله متد initState شیء State فراخوانی میشود.
وقتی ویجت با پیکربندی جدید بازسازی میشود، عنصر از طریق متد update ویجت جدید را دریافت میکند. عنصر نوع ویجت جدید و قدیمی را مقایسه میکند: اگر انواع یکسان باشند، عنصر پیکربندی خود را بهروزرسانی میکند؛ در غیر این صورت عنصر جدا شده و عنصر جدیدی ایجاد میشود. به این حالت «تغییر ویجت» گفته میشود و دلیل از دست رفتن حالت هنگام تغییر نوع است.
هنگام حذف ویجت از Widget Tree، متد unmount بر روی عنصر فراخوانی میشود. عنصر از Element Tree حذف میشود، RenderObject از RenderObject Tree حذف میشود و برای StatefulWidget متد dispose شیء State فراخوانی میشود. پس از unmount، اگر ویجت دوباره در همان موقعیت ظاهر شود، عنصر میتواند دوباره استفاده شود.
کلیدها (Key) مکانیزم شناسایی عناصر هستند که به Flutter اجازه میدهند ویجتهای Widget Tree قدیمی و جدید را نه بر اساس موقعیت، بلکه بر اساس شناسه یکتا مطابقت دهد. کلیدها هنگام کار با لیستهای پویا که ترتیب عناصر میتواند تغییر کند حیاتی هستند: افزودن، حذف یا جابهجایی عناصر.
بدون کلید، Flutter عناصر را بر اساس موقعیت آنها در درخت مطابقت میدهد: عنصر در موقعیت ۰ درخت قدیمی با ویجت در موقعیت ۰ درخت جدید جایگزین میشود. اگر ترتیب تغییر کرده باشد، عناصر به هم میریزند و حالت ممکن است از بین برود یا به دادههای اشتباه متصل شود. کلید Flutter را مجبور میکند عنصر را بر اساس شناسه جستجو کند، نه بر اساس موقعیت.
ValueKey برای شناسایی عنصر از یک مقدار ساده (رشته، عدد) استفاده میکند. ObjectKey از ارجاع به یک شیء استفاده میکند — زمانی مناسب است که عنصر شناسه رشتهای پایداری ندارد. UniqueKey در هر ایجاد یک شناسه یکتا تولید میکند — زمانی استفاده میشود که هر نمونه ویجت باید یکتا باشد.
Column(
children: items.map((item) => TodoItem(
key: ValueKey(item.id),
title: item.title,
isDone: item.isDone,
)).toList(),
)
در این مثال، ValueKey با item.id تضمین میکند که هر TodoItem حالت خود را (مثلاً فوکوس فیلد ورودی) هنگام تغییر ترتیب عناصر در لیست حفظ کند. بدون کلید، عنصر در موقعیت اول حالت عنصر قبلی در همان موقعیت را دریافت میکرد.
حالت (State) در Flutter نه در ویجتها، بلکه در عناصر ذخیره میشود. وقتی StatefulWidget بازسازی شده و نمونه جدیدی از ویجت ایجاد میکند، StatefulElement مربوطه ارجاع به شیء State قدیمی را حفظ میکند. ویجت جدید به State موجود متصل میشود و این امکان حفظ دادهها بین بازسازیها را فراهم میکند.
هنگام بازسازی ویجت، Flutter نمونه جدیدی از StatefulWidget ایجاد میکند، اما StatefulElement مربوطه در Element Tree باقی میماند. عنصر متد update را در State فراخوانی کرده و ویجت جدید را منتقل میکند. به این ترتیب شیء State و دادههایش حفظ میشوند. از دست رفتن حالت فقط هنگام تغییر نوع ویجت، تغییر کلید یا حذف عنصر از درخت رخ میدهد.
InheritedElement عنصر ویژهای است که به عناصر فرزند اجازه میدهد بدون انتقال صریح از طریق سازندهها، دادهها را از InheritedWidget والد دریافت کنند. وقتی InheritedWidget تغییر میکند، InheritedElement همه عناصر وابسته را مطلع میکند و آنها بازسازی میشوند. این مکانیزم اساس Theme، MediaQuery و Provider است.
Element Tree حافظه مصرف میکند و بر سرعت رندر اول تأثیر میگذارد. هر عنصر مقدار مشخصی حافظه اشغال میکند: ارجاع به ویجت، ارجاع به والد، فهرست عناصر فرزند، اسلات و فیلدهای اضافی برای RenderObjectElement. بهینهسازی Element Tree زمان راهاندازی را کاهش داده و مصرف حافظه را کم میکند.
Flutter هنگام بازسازی سعی میکند عناصر را دوباره استفاده کند. اگر ویجت در پیکربندی جدید نوع و کلید یکسانی داشته باشد، عنصر دوباره ساخته نمیشود — بهروزرسانی میشود. این بسیار سریعتر از ایجاد عنصر جدید و نصب آن است. اما هنگام تغییر نوع یا کلید، عنصر قدیمی جدا میشود و عنصر جدید از صفر ساخته میشود.
RepaintBoundary یک RenderRepaintBoundary جداگانه در RenderObject Tree ایجاد میکند که بخشی از درخت را ایزوله میکند. در سطح Element Tree، RepaintBoundary عنصر ویژهای ایجاد نمیکند — از SingleChildRenderObjectElement استفاده میکند. تفاوت در سطح RenderObject نمایان میشود: هنگام تغییر محتوا، فقط ناحیه ایزولهشده RepaintBoundary دوباره رنگ میشود.
| عملیات | بدون RepaintBoundary | با RepaintBoundary |
|---|---|---|
| رنگآمیزی مجدد | کل صفحه | فقط ناحیه ایزولهشده |
| زمان | ~۱۶ میلیثانیه در ۶۰ FPS | ~۲ تا ۵ میلیثانیه |
| حافظه | حداقل | + چند کیلوبایت برای هر لایه |
همانطور که جدول نشان میدهد، RepaintBoundary با ایزوله کردن ناحیه متغیر، زمان رنگآمیزی مجدد را بهطور قابل توجهی کاهش میدهد. در سطح Element Tree این نیاز به پیکربندی اضافی ندارد — کافی است ویجت متغیر را در RepaintBoundary بپیچید.
سؤالات متداول
Widget Tree پیکربندی است که در هر rebuild دوباره ساخته میشود. Element Tree ساختار پایداری است که بین بهروزرسانیها حفظ میشود و حالت، RenderObject و چرخه حیات ویجتها را مدیریت میکند.
بدون Element Tree، Flutter مجبور بود در هر تغییر حالت، RenderObject Tree را دوباره بسازد که باعث تأخیرهای قابل توجه میشد. Element Tree با حفظ RenderObject و State امکان اعمال فقط حداقل تغییرات را فراهم میکند.
عنصر زمانی حذف میشود که ویجت مربوطه از Widget Tree ناپدید شود، یا زمانی که نوع ویجت (مثلاً جایگزینی Column با Row) یا کلید تغییر کند. هنگام جدا شدن، dispose در State فراخوانی میشود.
کلیدها الگوریتم تطبیق را تغییر میدهند: Flutter به جای جستجوی عنصر بر اساس موقعیت، آن را بر اساس مقدار کلید جستجو میکند. این امکان حفظ حالت هنگام تغییر ترتیب یا تعداد ویجتها را فراهم میکند.
بله، از طریق BuildContext که انتزاعی از عنصر است. متدهای findAncestorWidgetOfExactType و dependOnInheritedWidgetOfExactType با بالا رفتن در درخت عناصر روی Element Tree کار میکنند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید