برنامه نویسی

درک و اجتناب از بازسازی اجزای غیرمنتظره در فلاتر

Summarize this content to 400 words in Persian Lang

کمی زمینه

اخیراً با مشکلی روبرو شدم که چند ساعت طول کشید تا بفهمم چه اتفاقی دارد می افتد. بیایید مستقیماً به مثال شیرجه بزنیم:

مولفه زیر را تصور کنید:

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

@override
StateCustomButton> createState() => _CustomButtonState();
}

class _CustomButtonState extends StateCustomButton> {
@override
void initState() {
print(‘INIT STATE CUSTOM BUTTON’);
super.initState();
}

@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {},
child: const Text(“Do something”),
);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ساده است، درست است؟ اما این initState خیلی سردرد به من داد

اساساً هر بار که صفحه وارد یا خارج می شود loading ایالت، initState تحریک شد. همانطور که می دانیم، initState باید فقط یک بار اجرا شود، زمانی که کامپوننت برای اولین بار روی صفحه قرار می گیرد.

بنابراین از خودم پرسیدم: چه چیزی باعث تخریب و بازسازی مکرر این مؤلفه شد؟ پاسخ ساده اما جالب است. نگاهی بیندازید:

چه زمانی loading بیشتر از true یا false

به یک مؤلفه پیچیده فکر کنید که در آن چندین سطح بارگذاری وجود دارد: از والد و از خود مؤلفه. یک مثال خوب یک لیست TODO است. غیرفعال کردن کل لیست فقط برای به روز رسانی یک مورد در باطن، تجربه خوبی نخواهد بود.

ما می توانیم رویکردی مانند این داشته باشیم:

در اینجا ما جهانی را داریم loading لیست و بارگیری جداگانه هر مورد. پس مشکل کجاست؟

ببینید چه اتفاقی می‌افتد وقتی ما آن را تغییر می‌دهیم loading وضعیت:

flutter: PAGE initState
flutter: PAGE BUILD
flutter: List Item initState
flutter: List Item BUILD
flutter: PAGE BUILD
flutter: List Item initState
flutter: List Item BUILD

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توجه داشته باشید که initState از List Item دو بار فراخوانی می شود، در حالی که صفحه نمایش تنها یک بار فراخوانی می شود. در لیستی با آیتم های ساده، این ممکن است مشکل بزرگی به نظر نرسد، اما وقتی در مورد لیست های پیچیده تر یا صفحه ای صحبت می کنیم که شامل اجزای وارد شده از ویژگی های دیگر با ویژگی های خاص خود می شود. initState روال، مشکل به راحتی می تواند تشدید شود. آیا می توانید ببینید که این ممکن است به کجا منجر شود؟

برای مثال، تصور کنید که هر بار ما List Item یک رویداد view را به یک سرویس Analytics ارسال می کند و این اتفاق در کامپوننت رخ می دهد initState. داده‌های مربوط به نماهای این ویجت به دلیل این “مشکل” به میزان قابل توجهی افزایش می یابد.

آیا راه حل هایی وجود دارد؟

البته! اما راه حل بستگی به مقیاس مشکل دارد.

در مورد بالا، ارسال اطلاعات نمای کامپوننت قبل از نمایش لیست، آسان تر خواهد بود تا در خود مؤلفه. این یک احتمال است. با این حال، در برنامه های بزرگتر، مدیریت همه چیز در یک مکان پایدار نیست.

نکته اصلی این است که دقیقاً بدانید از وضعیت بارگذاری خود در کجا استفاده کنید و چه زمانی آن را بخش بندی کنید.

من هنگام استفاده از کتابخانه shimmer با این مشکل خاص مواجه شدم. افکتی که در بالا استفاده کردم با آن ایجاد شد. هر بار که بارگذاری یک جزء تمام می شد، داده های یک ورودی پاک می شد، دقیقاً به این دلیل initState جزء در حال پاکسازی بود TextEditingController.

class CustomShimmer extends StatelessWidget {
final Widget child;
final bool loading;
final Color baseColor;
final Color highlightColor;

const CustomShimmer({
super.key,
required this.child,
this.loading = false,
this.baseColor = Colors.black,
this.highlightColor = Colors.white60,
});

@override
Widget build(BuildContext context) {
if (loading) {
return Shimmer.fromColors(
baseColor: baseColor,
highlightColor: highlightColor,
child: child,
);
}

return child;
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همانطور که گفته شد، هر بار که مولفه تغییر حالت می دهد، فرزند ما از بین می رود و دوباره خلق می شود. مهم است که روشن شود که این مشکل با کتابخانه نیست. اگر یک بود CircularProgressIndicator، همین اتفاق می افتاد.

نتیجه گیری

هدف این پست برجسته کردن چیز ساده ای بود که به راحتی می تواند مورد توجه قرار نگیرد و در آینده منجر به ایجاد مشکل در هیئت مدیره شما شود. مراقب این جزئیات باشید! 😊

کمی زمینه

اخیراً با مشکلی روبرو شدم که چند ساعت طول کشید تا بفهمم چه اتفاقی دارد می افتد. بیایید مستقیماً به مثال شیرجه بزنیم:

مولفه زیر را تصور کنید:

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

  @override
  StateCustomButton> createState() => _CustomButtonState();
}

class _CustomButtonState extends StateCustomButton> {
  @override
  void initState() {
    print('INIT STATE CUSTOM BUTTON');
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () {},
      child: const Text("Do something"),
    );
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ساده است، درست است؟ اما این initState خیلی سردرد به من داد

اساساً هر بار که صفحه وارد یا خارج می شود loading ایالت، initState تحریک شد. همانطور که می دانیم، initState باید فقط یک بار اجرا شود، زمانی که کامپوننت برای اولین بار روی صفحه قرار می گیرد.

بنابراین از خودم پرسیدم: چه چیزی باعث تخریب و بازسازی مکرر این مؤلفه شد؟ پاسخ ساده اما جالب است. نگاهی بیندازید:

چه زمانی loading بیشتر از true یا false

به یک مؤلفه پیچیده فکر کنید که در آن چندین سطح بارگذاری وجود دارد: از والد و از خود مؤلفه. یک مثال خوب یک لیست TODO است. غیرفعال کردن کل لیست فقط برای به روز رسانی یک مورد در باطن، تجربه خوبی نخواهد بود.

ما می توانیم رویکردی مانند این داشته باشیم:

نمونه-درباره-حالات-بارگذاری

در اینجا ما جهانی را داریم loading لیست و بارگیری جداگانه هر مورد. پس مشکل کجاست؟

ببینید چه اتفاقی می‌افتد وقتی ما آن را تغییر می‌دهیم loading وضعیت:

flutter: PAGE initState
flutter: PAGE BUILD
flutter: List Item initState
flutter: List Item BUILD
flutter: PAGE BUILD
flutter: List Item initState
flutter: List Item BUILD
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توجه داشته باشید که initState از List Item دو بار فراخوانی می شود، در حالی که صفحه نمایش تنها یک بار فراخوانی می شود. در لیستی با آیتم های ساده، این ممکن است مشکل بزرگی به نظر نرسد، اما وقتی در مورد لیست های پیچیده تر یا صفحه ای صحبت می کنیم که شامل اجزای وارد شده از ویژگی های دیگر با ویژگی های خاص خود می شود. initState روال، مشکل به راحتی می تواند تشدید شود. آیا می توانید ببینید که این ممکن است به کجا منجر شود؟

برای مثال، تصور کنید که هر بار ما List Item یک رویداد view را به یک سرویس Analytics ارسال می کند و این اتفاق در کامپوننت رخ می دهد initState. داده‌های مربوط به نماهای این ویجت به دلیل این “مشکل” به میزان قابل توجهی افزایش می یابد.

آیا راه حل هایی وجود دارد؟

البته! اما راه حل بستگی به مقیاس مشکل دارد.

در مورد بالا، ارسال اطلاعات نمای کامپوننت قبل از نمایش لیست، آسان تر خواهد بود تا در خود مؤلفه. این یک احتمال است. با این حال، در برنامه های بزرگتر، مدیریت همه چیز در یک مکان پایدار نیست.

نکته اصلی این است که دقیقاً بدانید از وضعیت بارگذاری خود در کجا استفاده کنید و چه زمانی آن را بخش بندی کنید.

من هنگام استفاده از کتابخانه shimmer با این مشکل خاص مواجه شدم. افکتی که در بالا استفاده کردم با آن ایجاد شد. هر بار که بارگذاری یک جزء تمام می شد، داده های یک ورودی پاک می شد، دقیقاً به این دلیل initState جزء در حال پاکسازی بود TextEditingController.

class CustomShimmer extends StatelessWidget {
  final Widget child;
  final bool loading;
  final Color baseColor;
  final Color highlightColor;

  const CustomShimmer({
    super.key,
    required this.child,
    this.loading = false,
    this.baseColor = Colors.black,
    this.highlightColor = Colors.white60,
  });

  @override
  Widget build(BuildContext context) {
    if (loading) {
      return Shimmer.fromColors(
        baseColor: baseColor,
        highlightColor: highlightColor,
        child: child,
      );
    }

    return child;
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همانطور که گفته شد، هر بار که مولفه تغییر حالت می دهد، فرزند ما از بین می رود و دوباره خلق می شود. مهم است که روشن شود که این مشکل با کتابخانه نیست. اگر یک بود CircularProgressIndicator، همین اتفاق می افتاد.

نتیجه گیری

هدف این پست برجسته کردن چیز ساده ای بود که به راحتی می تواند مورد توجه قرار نگیرد و در آینده منجر به ایجاد مشکل در هیئت مدیره شما شود. مراقب این جزئیات باشید! 😊

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا