Flutter 父组件更新时 不更新子组件 防止子组件rebuild

26 min read
//should_rebuild_widget

library should_rebuild_widget;

import 'package:flutter/material.dart';

typedef ShouldRebuildFunction<T> = bool Function(T oldWidget, T newWidget);

class ShouldRebuild<T extends Widget> extends StatefulWidget {
  final T child;
  final ShouldRebuildFunction<T>? shouldRebuild;

  const ShouldRebuild({required this.child, this.shouldRebuild});

  @override
  ShouldRebuildState createState() => ShouldRebuildState<T>();
}

class ShouldRebuildState<T extends Widget> extends State<ShouldRebuild> {
  @override
  ShouldRebuild<T> get widget => super.widget as ShouldRebuild<T>;
  T? oldWidget;

  @override
  Widget build(BuildContext context) {
    final T newWidget = widget.child;
    if (oldWidget == null ||
        (widget.shouldRebuild == null
            ? true
            : widget.shouldRebuild!(oldWidget!, newWidget))) {
      oldWidget = newWidget;
    }
    return oldWidget as T;
  }
}
		

基本原理: 根据传入的 shouldRebuild 方法判定返回新或者旧组件

使用方法如下:

ShouldRebuild<VerifyCode>(
  shouldRebuild: (oldWidget, newWidget) =>oldWidget.dotCount != newWidget.dotCount,
  child: VerifyCode(onChanged: _loginController.getVerifyCode),
),

使用 const声明的组件

使用 const 声明的组件不会更新,其源码如下

Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
...
      if (child.widget == newWidget) {
        if (child.slot != newSlot)   // 如果新旧组件不相同就update
          updateSlotForChild(child, newSlot);
        return child; // 相同就直接返回child
      }
      if (Widget.canUpdate(child.widget, newWidget)) {
        if (child.slot != newSlot)
          updateSlotForChild(child, newSlot);
        child.update(newWidget);
        assert(child.widget == newWidget);
        assert(() {
          child.owner._debugElementWasRebuilt(child);
          return true;
        }());
        return child;
      }

...
}