{"id":14956379,"url":"https://github.com/borombo-git/lazx","last_synced_at":"2025-10-24T09:30:41.483Z","repository":{"id":46146793,"uuid":"356022207","full_name":"borombo-git/lazx","owner":"borombo-git","description":"A state management library based on the ViewModel design pattern for Flutter.","archived":false,"fork":false,"pushed_at":"2024-07-12T23:21:23.000Z","size":599,"stargazers_count":12,"open_issues_count":0,"forks_count":3,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-01-29T09:25:19.200Z","etag":null,"topics":["dart","flutter","flutter-package","library","state-management"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/borombo-git.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-08T19:11:15.000Z","updated_at":"2024-07-12T23:17:35.000Z","dependencies_parsed_at":"2024-07-13T00:19:23.598Z","dependency_job_id":null,"html_url":"https://github.com/borombo-git/lazx","commit_stats":{"total_commits":75,"total_committers":1,"mean_commits":75.0,"dds":0.0,"last_synced_commit":"4ed8ef82ad70804dbd4500bf1075601e10ca6651"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borombo-git%2Flazx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borombo-git%2Flazx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borombo-git%2Flazx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borombo-git%2Flazx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/borombo-git","download_url":"https://codeload.github.com/borombo-git/lazx/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237944095,"owners_count":19391588,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dart","flutter","flutter-package","library","state-management"],"created_at":"2024-09-24T13:12:56.370Z","updated_at":"2025-10-24T09:30:40.774Z","avatar_url":"https://github.com/borombo-git.png","language":"Dart","funding_links":["https://www.buymeacoffee.com/borombo"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/borombo-git/lazx/raw/main/images/lazx.png?raw=true\" alt=\"Lazx\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://github.com/BBorombo/lazx/actions\"\u003e\u003cimg src=\"https://github.com/BBorombo/lazx/workflows/Build/badge.svg\" alt=\"build\"\u003e\u003c/a\u003e\n\u003ca href=\"https://codecov.io/gh/BBorombo/lazx\"\u003e\u003cimg src=\"https://codecov.io/gh/BBorombo/lazx/branch/main/graph/badge.svg\" alt=\"codecov\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/BBorombo/lazx\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/BBorombo/lazx.svg?style=flat\u0026logo=github\u0026colorB=deeppink\u0026label=stars\" alt=\"Star on Github\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-purple.svg\" alt=\"License: MIT\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.buymeacoffee.com/borombo\" target=\"_blank\"\u003e\u003cimg src=\"https://cdn.buymeacoffee.com/buttons/default-orange.png\" alt=\"Buy Me A Coffee\" height=\"25px\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# Lazx\n\nA state management library based on the ViewModel design pattern for Flutter.  \nFrom a lazy dev for lazy devs. 🥱\n\n## Index\n- [Introduction](#introduction)\n- [Usage](#Usage)\n- [Examples](#examples)\n- [Motivation](#motivation)\n- [Contributing](#contributing)\n- [Articles \u0026 Videos](#articles-and-videos)\n- [Dart Version](#dart-version)\n- [Maintainers](#maintainers)\n- [FAQ](#faq)\n\n## Introduction\nLazx is a state-management library that makes it easy to handle reactive data, from your UI without having to think about how you will do it.\n\nIt's based on the **MVVM design pattern** and allows you to implement it in the easiest possible way.\n\nYou will not have to *handle many files, inherit many classes or think about the best way to implement it*, everything is done in a way that you just have to think about the logic and UI of your app, nothing more (and nothing less, I can't make your app for you 🤷‍♂️).\n\nEnough talking let's jump into the concrete things 👇\n\n## Usage\nLazx can be used in many ways and has been made so it can be adapted depending the situation you're facing. \n\nEverything is based around the use of the Lazx Widgets/Builders but before, you should understand the easy concept of... **MVVM applied with Lazx**.\n\n### MVVM with Lazx\n#### Intro : Lazx State\nEverything is about state in Flutter  which is not necessarly the case in other languages/platforms. For these reason, I've added the **managment of state inside the data** so it can be synced with the state of your views. \n\nI've determined **4 main states** :\n\n - **Initial** - Represent the default state for a data. Could be before a loading/success/error flow, or just the one default state. By default, every data/view will starts with this state.\n - **Loading** - Represent a loading state for the data, if applicable.\n - **Success** - Represent a success state for a data. Could also be for a loaded data.\n - **Error** - Represent an error state for a data, if applicable.\n\n#### The Model : Lazx Data \nFor those comming from the Android world a LazxData is a simple version of [LiveData](https://developer.android.com/topic/libraries/architecture/livedata) adapter to Flutter with a state managment. \n\nFor the other, it's a way to subscribe and listen to the changes of your data and introduce a state to it. \n```dart\n// Initialize your data \nLazxData\u003cint\u003e counter = LazxData\u003cint\u003e(0);\n\n// Access the current value \nfinal currentValue = counter.value;\n\n// Update the value/state \ncounter.push(counter.value + 1);\ncounter.push(-1, lxState: LxState.Error);\ncounter.setState(LxState.Loading);\n\n// Listen to value/state changes \ncounter.stream.listen((value) {  \n  print(value);  \n});\n\ncounter.state.listen((state) {  \n  print(state);  \n});\n```\n\n`LazxData` are made to be used inside view models 👇\n\n#### Lazx View Model - The View Model\n\nA view model is simply a class that will be **linked to a view and hold its data**. \nA `LazxViewModel` is exactly that, with the addition that your data are `LazxData` objects and you should declare them. \n\n\u003e You can totally use a LazxViewModel wihtout using LazxData's.\n\n```dart\nclass SimpleDemoViewModel extends LazxViewModel {  \n  LazxData\u003cint\u003e counter = LazxData\u003cint\u003e(0);  \n  \n  @override  \n  List\u003cLazxData\u003e get props =\u003e [counter];  \n  \n void increment() {  \n    counter.push(counter.value + 1);  \n  }  \n}\n```\nThe `props` getter is used to dispose all your `LazxData` listeners when the view model is disposed... at the same time that the view it's linked to.\n\nThe view model should be linked to a view, the Lazx Screen 👇 \n\n#### Lazx ~~Screen~~ View  - The View\nThe view will be **linked to only one view model**. \nI've called a view ~~LazxScreen~~ `LazxView` as usually, a there's a view model per screen, so you should use the `LazxView` on a widget that represent a screen for your app. \n\n\u003e Of course, you can totally use a `LazxView` for a portion of your screen (also known as Fragment in Android) \n\n```dart\nclass LxDemoScreen extends LazxView\u003cSimpleDemoViewModel\u003e {  \n  @override  \n  SimpleDemoViewModel getViewModel() =\u003e SimpleDemoViewModel();  \n  \n  @override  \n  Widget build(BuildContext context, SimpleDemoViewModel viewModel) {  \n    return Scaffold(  \n      backgroundColor: Colors.white,  \n      appBar: AppBar(  \n        title: Text('Lazx Screen Demo'),  \n      ),  \n      body: Center(  \n        child: Text('Too Lazx'),   \n      ),  \n    );  \n  }  \n}\n```\nThe function `getViewModel()` should be overrided to provide the view model of your screen. The viewModel will then be linked to your screen view.\n\nThe build function will be a bit different en give you access directly to your view Model. \n\nYou can of course access your view model in other Widgets down in the tree of you `LazxScreen` by using : \n\n```dart\n// Access view model from any widget down in the sub tree  \nviewModel\u003cSimpleDemoViewModel\u003e(context).doSomething();\n```\n\n### Lazx Useful classes\nI've added some classes to make the possibility to build big apps easier and match most of the use cases you will encounter.\n\n#### Lazx State\nThe `Lazx State` is almost the same as a `Lazx Data`, the only difference is that there's no data, juste a state to listen.\nThis could be useful when you only need a state for something that doesn't necessarily have a data.\n\n\n````dart\nLazxState request = LazxState();\n\n// Set the state\nrequest.setState(LxState.Loading);\n\n// Listen the state\nrequest.state.listen((state) {\n  print(state);\n});\n````\n\nThe `Lazx State` is made to be used with a `Lazx Listener`.\n\n#### Lazx Observer\nThe `Lazx Observer` is almost the same as a `Lazx Data`, the only difference is that there's no state, juste the data to listen.\nIt could be seen as an abstraction for an Rx Observer to a value.\n\n````dart\n// Initialize empty observer \nLazxObserver\u003cint?\u003e value = LazxObserver();\n// Or with an initial value \nLazxObserver\u003cString\u003e text = LazxObserver(initialValue: 'Hello');\n\n// Set the data\nvalue.set(1);\n\n// Listen the data\nvalue.observer.listen((data) {\n  print(data);\n});\n````\n\nThe `Lazx Observer` is made to be used inside a `Lazx Manager`.\n\n#### Lazx Response\nA `Lazx Response` is simply a class to facilitate the response you can get from your sever or data provider.\nIt will put it in a way that you can easily know if your request worked or not and act in consequences.\n````dart\n\n// A classic http request, handled with a LxResponse\nFuture\u003cLxResponse\u003cint\u003e\u003e getTime() async {\n  try {\n    final response = await dataSource.httpRequest();\n    if (response.statusCode == 200) {\n      // Return a success response\n      return LxResponse(success: true, data: response.data);\n    } else {\n      // Return an error response\n      return LxResponse(error: response.statusMessage);\n    }\n  } catch (e) {\n    // Return an error response\n    return LxResponse(error: e.toString());\n  }\n}\n\n// A function that handle the http request result\nvoid showResult() async{\n  final LxResponse\u003cint\u003e response = await getTime();\n  \n  //Know if your request succeded\n  final isSuccess = response.success;\n\n  //Get your data\n  final data = response.data;\n  print('Result : $data');\n\n  //Get the error if there is one \n  final error = response.error;\n  print('Error : $error');\n}\n````\n\nThe `Lazx Observer` is made to be used witht the class that will handle your requests, generally the repository.\n\n#### Lazx Manager\nThe `Lazx Manager` is simply a class made to manage your data globally inside your app.\nThe manager should be the connection between your repositories and your view models. You handle all your logic\ntransformation there.\n\nA `Lazx Manager` is just a little abstraction to handle the `Lazx Observer` that you could have in them.\n\n````dart\nclass UserManager extends LazxManager {\n  static UserManager? _instance;\n  factory UserManager() =\u003e _instance ??= UserManager._();\n\n  UserManager._();\n  \n  late LazxObserver\u003cUser?\u003e currentUser = LazxObserver();\n\n  @override\n  List\u003cLazxObserver\u003e get props =\u003e [currentUser];\n\n  //...\n}\n````\nUsually, my managers are singletons as I need them in multiples places in my app, but you can create them as you prefer.\n\n### Lazx Widgets \u0026 Builders\nLet's see how you can use your data/view model/manager in your different widgets. \n\n#### Lazx App\nA `Lazx App` is a widget that you will extends on the the root widget of your application.\nThis one will be used to handle your `Lazx Manager`s if you use them as singletons, to be able to dispose all the used\n`sink` when the app is finished and avoid memory leaks.\n\n```dart\nclass MyApp extends LazxApp {\n  \n  @override\n  List\u003cLazxManager\u003e get managers =\u003e [MyManager()];\n\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Lazx App',\n      theme: theme,\n      home: MyScreen(),\n    );\n   }\n}\n```\nAlso, `Lazx App` is an abstraction of a StatefulWidget, so you can override the classic `initState` and `dispose` function\n\n#### Lazx Builder\nThe easiest one, the `LazxBuilder` allows you to build a widget each time the value of your `LazxData` is updated.\n\u003e ⚠️ The state is not used with this builder\n\n```dart\nLazxBuilder\u003cint\u003e(  \n  data: viewModel.counter,  \n  builder: (context, value) {  \n    return Text('$value');  \n  }\n),\n```\nYou should pass a `LazxData` as the data and the builder will be called each time with the updated value.\n\n#### Lazx State Builder\nThe `LazxStateBuilder` is almost the same that the previous one but it takes the state of your data into consideration. \n\nYou will be able to have a \"builder\" function for each state : \n```dart\nLazxStateBuilder\u003cint\u003e(  \n  data: viewModel.counter,  \n  initial: (context, value) {  \n    return Text('$value');  \n  },  \n  loading: (context, value) {  \n    return CircularProgressIndicator();  \n  },  \n  success: (context, value) {  \n    return Text(\n      '$value',\n      style: TextStyle(color: Colors.green),\n    );  \n  }\n),\n```\nYou have a builder function with the name of each state. Only the `initial` one if mandatory, you can implement the other ones only if needed. \n\nThey will be called each time the state of your data is updated.\n\n#### Lazx State Widget \u0026 Data Builder\nFrom the previous builder, instead of having all the builder function for a state inside a builder (that could become long to write in one place if there's a lot of differences) you can have them directly inside a widget : \n\n```dart \nclass LxCounterText extends LazxStateWidget {  \n  @override  \n  Widget initial(BuildContext context, data) {  \n    return Text('$data');  \n  }  \n  \n  @override  \n  Widget loading(BuildContext context, data) {  \n    return CircularProgressIndicator();  \n  }  \n  \n  @override  \n  Widget success(BuildContext context, data) {  \n    return Text(  \n      '$data',  \n      style: TextStyle(color: Colors.green),\n    );  \n  }  \n}\n```\nThe same as for the builder, you don't have to override all the function, only the `initial` one is required.\n\nThen you cand use a `LazxDataBuilder` wich is simplier : \n\n```dart \nLazxDataBuilder(  \n  data: viewModel.counter,  \n  lxWidget: LxCounterText(),  \n),\n```\nThe behavior is the same than with the `LazxStateBuilder`.\n\n#### Lazx Multi Builder\nThe `LazxMultiBuilder` is like a `LazxBuilder` but it listen to multiple source of `LazxData` at the same time. \n\nThe widget is then rebuild each time one of the data is updated. \n\u003e ⚠️ The state is not used with this builder\n\u003e \n```dart\nLazxMultiBuilder(  \n  data: [viewModel.counter, viewModel.show],  \n  builder: (context, values) {  \n    return Text('Counter: ${values[0]} \u0026 Show: ${values[1]}');  \n  }\n),\n```\nThe `values` list will contain the values of the data in the same order as the list you passed in the `data` parameter.\n\nCheck the examples for more concrete usages 👇 \n\n## Examples\n- [Demo App ⚙️](https://github.com/borombo-git/lazx/tree/main/demos/demo) - A simple demo of all the Lazx Widgets/Builders\n- [Lazx Weather ☀️](https://github.com/borombo-git/lazx/tree/main/demos/lazx-weather) - A small weather app to showcase the usage of Lazx\n\n## Motivation\n\nSo... Why **Lazx** ?\n\nI'm originally an Android Developer and I learned and practiced Flutter and really enjoyed it. 💙\n\nThe thing is that **I'm really lazy** and when it comes to make a good and strong architecture for your app in Flutter, it becomes a bit complicated and too greedy in ressources.\n\nDepending on what you like (BloC, Redux, Provider...) you will have to create multiple files, handle multiples things, and I felt like I had to make **a whole logic and organization, just for the architecture and state management of my app**. 🤯\n\nSo after having done a few production apps with Flutter, I was really lazy to again, having to setup everything about architecture and state management.\n\nIn the other side, I had a really smooth structure for my apps in native Android development and really used to use it. As the other solutions in Flutter didn't really fit my needs and I couldn't find enough resources to use them at their fullest potential I finally decided to do the thing that every lazy person would do : **Make my own state management**. 🧐\n\nThat's how **Lazx** is born (with this fantastic and long searched name) 🐣\n\n## Contributing\n_Want to contribute to the project? Here are some points where you can contribute :_\n\n- Report bugs and scenarios that are difficult to implement\n- Report parts of the documentation that are unclear\n- Update the documentation / add examples\n- Implement new features/tests by making a pull-request\n- Adding documentation to the readme .\n- Write articles or make videos teaching how to use Lazx (they will be inserted in the Readme).\n\nAny contribution is welcomed!\n\n## Articles and Videos\nComing soon. 🎬\n\n## Dart Version\n- Dart 2: \u003e= 2.12\n\n## Maintainers\n- [Borombo](https://github.com/borombo-git)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fborombo-git%2Flazx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fborombo-git%2Flazx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fborombo-git%2Flazx/lists"}