flutter_obs 1.6.3 copy "flutter_obs: ^1.6.3" to clipboard
flutter_obs: ^1.6.3 copied to clipboard

a easy flutter state management, the source code is less than 100, but you can use it to implement global and local states

一个简单的响应式状态管理,它是对 ValueNotifier 进行的扩展:

  1. Obs - 创建响应式变量
  2. ObsBuilder - 响应式变量构建器

1. 局部使用 #

热刷新会重置状态,当父类引用此组件时,如果没有添加 const 修饰每次刷新也会重置状态, 原理很简单,如果触发了 build 方法响应式变量就会被重新创建,状态自然就被重置

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

  @override
  Widget build(BuildContext context) {
    final count = Obs(0);
    return ElevatedButton(
      onPressed: () => count.value++,
      child: ObsBuilder(builder: (context) => Text('count: ${count.value}')),
    );
  }
}

2. 使用 hook,弥补 StatelessWidget 的缺陷 #

为了稳定性,此库不依赖任何第三方库,所以移除掉了 flutter_hook 依赖及其相关代码,封装的代码很简单, 请看useObs

class Example extends HookWidget {
  const Example({super.key});

  @override
  Widget build(BuildContext context) {
    final count = useObs(0);
    return ElevatedButton(
      onPressed: () => count.value++,
      child: ObsBuilder(builder: (context) => Text('count: ${count.value}')),
    );
  }
}

3. 在 StatefulWidget 中使用 #

提示:你不需要在 dispose 生命周期中销毁它

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

  @override
  State<Example> createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  final count = Obs(0);

  @override
  void dispose() {
    super.dispose();
    // count.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () => count.value++,
      child: ObsBuilder(builder: (context) => Text('count: ${count.value}')),
    );
  }
}

4. 全局状态管理 #

定义一个全局状态非常简单,只需要将响应式变量放到 Widget 外部即可

// 全局响应式变量
final count = Obs(0);

// 或者使用类进行管理
class GlobalState {
  static final count = Obs(0);
}

// 对于全局状态,你可以放心地使用 StatelessWidget,因为状态已被移到外部
class Example extends StatelessWidget {
  const Example({super.key});

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () => GlobalState.count.value++,
      child: ObsBuilder(builder: (context) => Text('count: ${GlobalState.count.value}')),
    );
  }
}

5. 当组件被销毁时重置全局状态定义的所有响应式变量 #

先定义一个允许为空的控制器,当组件挂载时进行初始化,被销毁时将其设置为 null 即可

Controller? _controller;

Controller get controller {
  assert(_controller != null, 'Controller 还未初始化');
  return _controller!;
}

class Controller {
  final count = Obs(0);
  final flag = Obs(false);
}

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

  @override
  State<Example> createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  @override
  void initState() {
    super.initState();
    _controller = Controller();
  }

  @override
  void dispose() {
    super.dispose();
    controller = null;
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () => controller.count.value++,
      child: ObsBuilder(builder: (context) => Text('count: ${controller.count.value}')),
    );
  }
}

6. 依赖注入 #

Obs可以轻松和 InheritedWidget 或 Provider 进行集成,以下是 InheritedWidget 的使用示例, Provider 是对 InheritedWidget 进行的封装,用法都是一样

/// 创建依赖注入小部件
class ProviderData extends InheritedWidget {
  const ProviderData({
    required super.child,
    required this.count,
  });

  final Obs count;

  static ProviderData of(BuildContext context) =>
      context.dependOnInheritedWidgetOfExactType<ProviderData>()!;

  @override
  bool updateShouldNotify(ProviderData oldWidget) => true;
}

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

  @override
  Widget build(BuildContext context) {
    final count = Obs(0);
    return Scaffold(
      // 注入依赖
      body: ProviderData(
        count: count,
        child: Column(
          children: [
            ObsBuilder(builder: (context) {
              return Text('parent count: ${data.count.value}');
            }),
            const Child(),
          ],
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    // 子组件获取祖先注入的依赖
    final data = ProviderData.of(context);
    return ElevatedButton(
      onPressed: () {
        data.count.value++;
      },
      child: ObsBuilder(builder: (context) {
        return Text('child count: ${data.count.value}');
      }),
    );
  }
}

7. 手动刷新 #

Obs 提供了 auto 变量用于控制是否自动刷新页面

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

  @override
  Widget build(BuildContext context) {
    final count = Obs(0, auto: false);
    return ElevatedButton(
      onPressed: () {
        count.value++;
        count.notify(); // 手动刷新

        count.auto = false; // 你可以随时控制是否要自动刷新页面
        count.value++;
        // 处理其他逻辑...
        count.notify();
        count.auto = true;
      },
      child: ObsBuilder(builder: (context) => Text('count: ${count.value}')),
    );
  }
}

8. 添加监听函数 #

Obs提供了 watch 选项,在创建响应式变量的同时绑定监听逻辑,你还可以设置 immediate 选项触发立即执行一次监听函数, 它的触发时机便是执行了 notify 函数。

注意:oldValue 依赖于 setter 方法的执行,当你的响应式变量值是一个对象时,如果没有进行整个对象的赋值, 那么 setter 方法将无法拦截,会导致 oldValue 不会更新,这时,你需要手动修改 oldValue。

class GlobalState {
  static final enableResampling = Obs(
    true,
    immediate: true,
    watch: (newValue, oldValue) {
      GestureBinding.instance.resamplingEnabled = newValue;
    },
  );
}

9. ObsBuilder监听其他响应式变量 #

ObsBuilder 也提供了 watch 选项,与 Obs 不同的是,它接收 Obs 数组,当监听的任意一个变量发生变化时,都会重新构建小部件

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

  @override
  Widget build(BuildContext context) {
    final count1 = Obs(0);
    final count2 = Obs(0);
    return ElevatedButton(
      onPressed: () => count2.value++,
      child: ObsBuilder(
        // 当 count2 更新时,也会重建小部件,即使小部件构建函数中没有使用 count2 变量
        watch: [count2],
        builder: (context) => Text('count: ${count1.value}'),
      ),
    );
  }
}

10. 响应式变量 - 对象 #

之所以修改 List、Map 等对象时不会触发自动刷新,是因为 dart 只能通过 setter 方法拦截对象的更改, 如果你没有将整个对象进行赋值,那么 setter 方法无法拦截,所以自然无法触发自动刷新,这种情况下你有两个选择:

  1. 将整个对象进行赋值给 .value
  2. 手动执行 notify 方法触发刷新
class Example extends StatelessWidget {
  const Example({super.key});

  @override
  Widget build(BuildContext context) {
    final user = Obs({
      'name': 'hihi',
      'age': 20,
    });
    return ElevatedButton(
      onPressed: () {
        // 设置完整对象,List、DataModel 同理
        user.value = {
          ...user.value,
          'name': 'xx',
        };

        // 或者手动刷新
        user.value['name'] = 'xx';
        user.notify();
      },
      child: ObsBuilder(
        builder: (context) => Text('user name: ${user.value["name"]}'),
      ),
    );
  }
}

11. 注意事项 #

这种写法要尽量避免,它虽然不会引起泄漏,但会让 ObsBuilder 重建范围变大

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

  @override
  State<Example> createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  bool flag = false;

  @override
  Widget build(BuildContext context) {
    final count = Obs(0);

    return ObsBuilder(builder: (context) {
      return flag
          ? ObsBuilder(builder: (context) => Text('count: ${count.value}'))
          : Text('count: ${count.value}');
    });
  }
}

0
likes
150
points
99
downloads

Publisher

unverified uploader

Weekly Downloads

a easy flutter state management, the source code is less than 100, but you can use it to implement global and local states

Homepage

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on flutter_obs