miladtech_after_init

为有状态的小部件添加了一个 didInitState() 生命周期方法,您可以在其中安全地访问继承的小部件。

InheritedWidget 在 Flutter 框架中被广泛使用。许多状态管理包,如 ScopedModelProvider 也使用它。不幸的是,InheritedWidgets 无法从 StateinitState() 方法中访问。 Flutter 文档指出:

/// You cannot use [BuildContext.inheritFromWidgetOfExactType] from this
/// method. However, [didChangeDependencies] will be called immediately
/// following this method, and [BuildContext.inheritFromWidgetOfExactType] can
/// be used there.

此包由一个简单的 State 类 mixin 组成,它提供了一个名为 didInitState() 的新方法。它只会被调用 **一次**,在 initState() 之后,在 didChangeDependencies()build() 之前。您可以从该方法中安全地访问 InheritedWidgets,并使用它们来执行小部件的任何设置任务。

方法顺序

使用此库,State 方法按以下顺序调用:

  1. initState()
  2. didInitState()← **新增!**
  3. didChangeDependencies()
  4. build()

示例

import 'package:flutter/material.dart';
import 'package:miladtech_after_init/miladtech_after_init.dart';

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        body: Example(),
      ),
    ),
  );
}

class Example extends StatefulWidget {
  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> with AfterInitMixin<Example> {
  Size size;

  /// This gets called first, as usual.
  @override
  void initState() {
    super.initState();
    // Your code here
  }

  /// This gets called after initState(), only once.
  /// Safely access inherited widgets here.
  @override
  void didInitState() {
    // No need to call super.didInitState().
    // setState() is not required because build() will automatically be called by Flutter.
    size = MediaQuery.of(context).size;
  }

  /// This gets called after didInitState().
  /// And anytime the widget's dependencies change, as usual.
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    // Your code here
  }

  /// Finally this gets called, as usual.
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text(size.toString()),
    );
  }
}

这只是一个简单的例子。您通常会在 didInitState() 中执行更有用的操作,例如访问设置数据或订阅来自 InheritedWidgetStream

替代方案

initState() 限制的一个典型解决方法是延迟执行需要访问 InheritedWidget 的代码。

@override
void initState() {
  super.initState();
  WidgetsBinding.instance.addPostFrameCallback((_) {
    print(MediaQuery.of(context).size);
  });
}

但是,这会导致您的代码在 build() 方法之后执行,这可能不是您想要的。

单元测试

此包附带单元测试,以验证 didInitState() 只被调用一次,并且 State 方法按上述顺序调用。

鸣谢

此包由 MiladTech 创建。

GitHub

查看 Github