Skip to content

InheritedWidget

InheritedWidget 是 Flutter 实现数据从上向下共享的基础机制。Provider 等状态管理方案都是基于它封装的。

基本原理

InheritedWidget 允许数据在 Widget 树中自顶向下传递,子组件可以通过 BuildContext 获取最近父级提供的 InheritedWidget 数据。当数据变化时,依赖该数据的子组件会自动重建。

手动实现示例

1. 创建 InheritedWidget

dart
class CounterData extends InheritedWidget {
  const CounterData({
    super.key,
    required this.count,
    required this.onIncrement,
    required super.child,
  });

  final int count;
  final VoidCallback onIncrement;

  // 静态方法:让子组件方便获取数据
  static CounterData of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<CounterData>()!;
  }

  // 决定是否通知依赖的子组件重建
  @override
  bool updateShouldNotify(CounterData oldWidget) {
    return count != oldWidget.count;
  }
}

2. 在 Widget 树中提供数据

dart
class CounterProvider extends StatefulWidget {
  final Widget child;

  const CounterProvider({super.key, required this.child});

  @override
  State<CounterProvider> createState() => _CounterProviderState();
}

class _CounterProviderState extends State<CounterProvider> {
  int _count = 0;

  void _increment() {
    setState(() => _count++);
  }

  @override
  Widget build(BuildContext context) {
    return CounterData(
      count: _count,
      onIncrement: _increment,
      child: widget.child,    // 子树
    );
  }
}

3. 在子组件中使用

dart
class CounterDisplay extends StatelessWidget {
  const CounterDisplay({super.key});

  @override
  Widget build(BuildContext context) {
    final data = CounterData.of(context);  // 获取数据
    return Text('计数: ${data.count}');
  }
}

class CounterButton extends StatelessWidget {
  const CounterButton({super.key});

  @override
  Widget build(BuildContext context) {
    final data = CounterData.of(context);  // 获取方法
    return ElevatedButton(
      onPressed: data.onIncrement,
      child: const Text('+1'),
    );
  }
}

// 使用
CounterProvider(
  child: Scaffold(
    body: Column(
      children: const [
        CounterDisplay(),
        CounterButton(),
      ],
    ),
  ),
)

核心方法

dependOnInheritedWidgetOfExactType

dart
// 注册依赖 —— 数据变化时会重建该组件
static CounterData of(BuildContext context) {
  return context.dependOnInheritedWidgetOfExactType<CounterData>()!;
}

getInheritedWidgetOfExactType(不注册依赖)

dart
// 不注册依赖 —— 数据变化时不会重建(只读取一次值)
static CounterData read(BuildContext context) {
  return context.getInheritedWidgetOfExactType<CounterData>()!;
}

updateShouldNotify

dart
@override
bool updateShouldNotify(CounterData oldWidget) {
  // 返回 true → 通知依赖的子组件重建
  // 返回 false → 不通知
  return count != oldWidget.count;
}

实际使用建议

手写 InheritedWidget 比较繁琐。在实际项目中,推荐直接使用 Provider,它是对 InheritedWidget 的优雅封装。

TIP

理解 InheritedWidget 的原理有助于你理解 Provider 等上层框架的工作方式,但在实际开发中通常不需要手动实现。

基于 Flutter 官方文档整理