You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter调用dependOnInheritedWidgetOfExactType返回null的问题排查与解决

Flutter InheritedWidget查找返回null问题排查

问题描述

我尝试使用InheritedWidget方案沿Widget树向下共享状态,为此开发了一个简易计数器应用,可对计数器执行加、减、乘、除任意操作。这是小型演示项目,未遵循开发最佳实践。
代码行context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>()不知为何返回null,对照示例和官方文档,该方法应该能在Widget树中定位到MyInheritedWidget并返回实例,但Flutter工具一直提示该值为null,断言校验也确认该值确实为null。
请问该方法返回失败的原因是什么?需要如何调整才能正确获取到MyInheritedWidget实例?

问题代码

文件:main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Counter(),
    );
  }
}

class Counter extends StatefulWidget {
  const Counter({Key? key}) : super(key: key);

  @override
  CounterState createState() => CounterState();
}

class CounterState extends State<Counter> {
  int counter = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter App'),
        centerTitle: true,
      ),
      body: MyInheritedWidget(
        counterState: this,
        child: Builder(
          builder: (BuildContext innerContext) {
            return CounterViewer(
                counterState: MyInheritedWidget.of(context).counterState);
          },
        ),
      ),
    );
  }

  void addCounter(int value) {
    setState(() {
      counter++;
    });
  }

  void subtractCounter(int value) {
    setState(() {
      counter--;
    });
  }

  void multiplyCounter(int value) {
    setState(() {
      counter *= value;
    });
  }

  void divideCounter(int value) {
    setState(() {
      counter = (counter / value).toInt();
    });
  }
}

class MyInheritedWidget extends InheritedWidget {
  final CounterState counterState;

  const MyInheritedWidget(
      {Key? key, required Widget child, required this.counterState})
      : super(key: key, child: child);

  static MyInheritedWidget of(BuildContext context) {
    final MyInheritedWidget? widget =
        context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();

    assert(widget != null);
    return widget!;
  }

  @override
  bool updateShouldNotify(covariant InheritedWidget oldWidget) {
    return true;
  }
}

class CounterViewer extends StatelessWidget {
  final CounterState counterState;

  const CounterViewer({Key? key, required this.counterState}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Container(
          color: Colors.green.shade200,
          width: MediaQuery.of(context).size.width,
          height: 180,
          child: Center(
            child: Text(
              '220',
              style: TextStyle(
                color: Colors.grey.shade50,
                fontSize: 60,
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
        ),
        Container(
          color: Colors.grey.shade300,
          padding: EdgeInsets.symmetric(vertical: 16),
          child: Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              ElevatedButton(
                onPressed: () {},
                child: Text('Add'),
              ),
              ElevatedButton(
                onPressed: () {},
                child: Text('Subtract'),
              ),
              ElevatedButton(
                onPressed: () {},
                child: Text('Multiply'),
              ),
              ElevatedButton(
                onPressed: () {},
                child: Text('Divide'),
              ),
            ],
          ),
        )
      ],
    );
  }
}

原因与解决方案

根本原因

dependOnInheritedWidgetOfExactType方法是从传入的context对应的Widget节点开始,向上遍历父节点查找指定类型的InheritedWidget。问题代码里调用MyInheritedWidget.of(context)时传入的是CounterState的build方法入参context,这个context对应的节点在MyInheritedWidget的上层,向上自然找不到对应的InheritedWidget实例,所以返回null。

修复方案

将of方法的入参替换为Builder构造器提供的innerContext,这个context对应的节点是MyInheritedWidget的子节点,向上遍历就能找到目标实例。修复后的代码如下:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('Counter App'),
      centerTitle: true,
    ),
    body: MyInheritedWidget(
      counterState: this,
      child: Builder(
        builder: (BuildContext innerContext) {
          return CounterViewer(
              counterState: MyInheritedWidget.of(innerContext).counterState);
        },
      ),
    ),
  );
}

内容的提问来源于stack exchange,提问作者Ariel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 19:36:04