无状态

一个有状态的、无状态的状态管理包,它不是无状态的。

stateless coverage style: very good analysis License: MIT pub package


简介

该包的目的是看看我们是否可以在不关心状态管理的情况下进行状态管理。Stateless 的学习曲线应该是最小的,开发者从已知的 Flutter API 中获得的知识应该是可转移的,例如 initStatedisposebuild

入门

在你的 flutter 项目中,在你的 pubspec.yaml 中添加以下内容

  dependencies:
    stateless: ^0.1.0

用法

经典的 Flutter 计数器 Widget,使用 Stateless 重写

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

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Stateless Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(primarySwatch: Colors.blue),
      home: MyHomePage(title: 'Stateless Demo Home Page'),
    );
  }
}

// We define the interface that will describe our state data.
abstract class MyCounterState {
  late int counter;
}

// We extends from Stateless to create our stateless stateful widget.
class MyHomePage extends Stateless implements MyCounterState {
  MyHomePage({super.key, required this.title});

  final String title;

  @override
  void initState() {
    super.initState();
    // Initialize our state data.
    counter = 0;
  }

  void showSnackBar() {
    // We can access the BuildContext from anywhere in our widget.
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('The count is at: $counter')),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: const Center(child: MyCounterText()),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            // Update the counter by just simply incrementing it.
            onPressed: () => counter++,
            tooltip: 'Increment',
            child: const Icon(Icons.add),
          ),
          const SizedBox(height: 8),
          FloatingActionButton(
            onPressed: showSnackBar,
            tooltip: 'Show SnackBar',
            child: const Icon(Icons.lightbulb),
          ),
        ],
      ),
    );
  }
}

如你所见,API 与普通 Flutter widgets 几乎没有区别,通过继承 Stateless 并实现我们的状态接口,我们可以简单地更新接口属性,它会自动知道其状态已更改,从而触发重建。

在子项中访问状态数据

很多时候你想在树中的父级访问状态数据,Stateless 可以为你做到这一点!

让我们将上面的计数器应用重新设想为两部分,一部分是 Stateless widget,第二部分是一个正常的 StatelessWidget,它显示计数器值。

class MyHomePage extends Stateless implements MyCounter {
  ... 

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      // We build our custom text counter widget here.
      body: const Center(child: MyCounterText()),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            onPressed: () => counter++,
            tooltip: 'Increment',
            child: const Icon(Icons.add),
          ),
          const SizedBox(height: 8),
          FloatingActionButton(
            onPressed: showSnackBar,
            tooltip: 'Show SnackBar',
            child: const Icon(Icons.lightbulb),
          ),
        ],
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    // We can then observe our MyHomePage for state changes.
    final myHomePage = context.observe<MyHomePage>();

    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        const Text('You have pushed the button this many times:'),
        Text(
          '${myHomePage.counter}',
          style: Theme.of(context).textTheme.headline4,
        ),
      ],
    );
  }
}

我们的 MyCounterText widget 可以简单地观察我们 MyHomePage 的状态并从中读取当前的 counter 值。

贡献

有兴趣贡献吗?我们喜欢 Pull Request!有关更多信息,请参阅 贡献 文档。

GitHub

查看 Github