一个轻量级的状态管理,具有React语法。

通过使用Reactter,您可以获得

功能

  • 使用熟悉的语法,如UseStateUseEffectUseContext自定义hooks等。
  • 创建自定义hooks以重用功能。
  • 显著减少样板代码。
  • 提高代码可读性。
  • 单向数据流。
  • 一种在应用程序中共享全局信息的简便方法。

用法

UseState

class AppContext extends ReactterContext {
        
    // You can create the state here and add it to dependencies in 
    // constructor with listenHooks() */
    final username = UseState<String>("");

    AppContext(){
        listenHooks([username]);
    }

    // We recommend to give the context to the state this way:
    // With this, you no longer need to put it in listenHooks()
    // which is cleaner */
    late final firstName = UseState<String>("Leo", context: this);
    late final lastName = UseState<String>("León", context: this);
}

您还可以创建任何其他类,并设置一个UseState属性来共享状态。

class Global {
  static final currentUser = UseState<User?>(null);
}

但如果您需要响应式小部件,则需要使用ReactterContext或将此属性传递给ReactterContext

请参阅自定义Hooks示例。

UseEffect

AppContext(){

    UseEffect((){

      userName.value = firstName + lastName;

    }, [firstName, lastName]);

}

它应该在ReactterContext构造函数内部使用。

UseProviderUseContext

UseProvider(
    contexts: [
        UseContext(
            () => AppContext(),
            init: true,
        )
    ],
    builder: (context, _) {
        
        final appContext1 = context.of<AppContext>();

        final appContext2 = context.of<AppContext>((ctx) => [ctx.userName]);

        final appContext3 = context.ofStatic<AppContext>();

        return Text(appContext1.username.value);
    }
);

读取值

如上例所示,您可以通过三种不同的方式从上下文中读取值

  1. context.of<AnyContext>():获取上下文的所有状态监听器。
  2. context.of<AnyContext>((ctx) => [ctx.anyState]):获取特定状态的监听器以进行重建,您可以根据需要使用任意数量。
  3. context.ofStatic<AppContext>():读取所有状态,但在更改时不会重建。

UseAsyncState

class AppContext extends ReactterContext {

    late final userName =
        UseAsyncState<String>("Init state", fillUsername, context: this);

    Future<String> fillUsername() async {
        final userFromApi = await getUserName();

        return userFromApi;
    }

    // You should use anyAsyncState.resolve() to resolve the state
    onClickGetUser(){
        userName.resolve();
    }

}

您可以在任何地方执行resolve()

UseAsyncState.when

userContext.userName.when(

    standby: (value) => Text("Standby: ${value}"),

    loading: () => const CircularProgressIndicator(),

    done: (value) => Text(value),

    error: (error) => const Text("Unhandled exception: ${error}"),
)

<AnyAsyncState>.when接收四个函数,并始终返回一个widget,以根据状态的状态处理视图

  • standby:当状态具有初始值时。
  • loading:当状态的请求正在检索值时。
  • done:当请求完成时。
  • error:如果请求中发生任何错误。

自定义Hooks

mixin UseCart on ReactterHook {
    late final cart = UseState<Cart?>(null, context: this);

    addProductToCart(Product product) {
        final oldProducts = cart.value.products;

        cart.value = cart.value?
            .copyWith(products: [...oldProducts, product]);
    }
}

您可以使用如下方式

class UserContext extends ReactterContext with UseCart {
  final user = Global.currentUser;

  UserContext() {
    UseEffect(() {
      cart.value = api.getUserCart(user.value?.id ?? 0);
    }, [user]);
  }
}

我们建议使用mixins来创建hooks,因为它们易于注入变量,但任何扩展ReactterHook的类都可以成为自定义hook

ReactterContext上的生命周期方法

@override
awake() {}

@override
willMount() {}

@override
didMount() {}

@override
willUnmount() {}

所有ReacterContext都有这些生命周期方法

  • awake:在实例开始构建时执行。
  • willMount:在依赖项widget挂载到树之前执行。
  • didMount:在依赖项widget挂载到树之后执行。
  • willUnmount:当widget从树中移除时执行。

路线图

我们也在创建一个文档页面,并制作YouTube教程。

我们希望为Reactter添加更多功能,以下是我们考虑的按优先级排序的

V2

  • 测试
    • 使Reactter易于测试。
  • 创建
    • 可以选择从具有不同ID的上下文创建相同的实例,这对于列表widget非常有用,每个widget都将拥有自己的状态。
  • 延迟UseContext
    • 在需要之前不要初始化上下文。
  • 子widget渲染可选
    • 保存一个不会在状态更改时重新渲染的子widget。
  • ReactterComponent
    • 一个StatelessWidget,它将向所有widget公开ReactterContext状态,而无需编写context.of<T>(),只需state.someProp
  • Equatable
    • 在处理对象或列表时,移除状态中的alwaysUpdate属性。

ReactterComponents(新包)

  • 按钮(几乎准备好发布)
  • 应用栏
  • 底部栏
  • Snackbar
  • 抽屉
  • 浮动操作
  • 模态框
  • 输入框

警告

Reactter已刚离开开发阶段,您可以在生产环境中使用它,但用于小型应用程序时需谨慎,我们正在努力使其更具可测试性,并考虑状态管理的所有可能情况。API可能会因Roadmap而发生变化。

贡献

如果您想贡献,请随时在Reactter存储库中创建issue或pull request。

您可以

  • 添加新的自定义hooks。
  • 添加新的widget。
  • 添加示例。
  • 报告bug。
  • 报告难以实现的情况。
  • 报告不明确的错误。
  • 报告不明确的文档。
  • 撰写文章或制作视频,讲解如何使用Reactter

任何想法都欢迎!

作者

版权所有 (c) 2022 2devs.io

GitHub

查看 Github