{"id":13548529,"url":"https://github.com/nank1ro/solidart","last_synced_at":"2025-04-04T16:12:02.135Z","repository":{"id":65181161,"uuid":"584456409","full_name":"nank1ro/solidart","owner":"nank1ro","description":"Signals in Dart and Flutter, inspired by SolidJS","archived":false,"fork":false,"pushed_at":"2025-03-12T17:40:26.000Z","size":11640,"stargazers_count":185,"open_issues_count":1,"forks_count":6,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-03T11:47:27.585Z","etag":null,"topics":["dart","flutter","signals","solidart","solidjs","state-management"],"latest_commit_sha":null,"homepage":"https://docs.page/nank1ro/solidart","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/nank1ro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"nank1ro","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"custom":null}},"created_at":"2023-01-02T16:10:10.000Z","updated_at":"2025-04-03T01:01:38.000Z","dependencies_parsed_at":"2023-10-03T21:28:38.616Z","dependency_job_id":"51501d36-0865-4394-b873-8974d8ec68c2","html_url":"https://github.com/nank1ro/solidart","commit_stats":null,"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nank1ro%2Fsolidart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nank1ro%2Fsolidart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nank1ro%2Fsolidart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nank1ro%2Fsolidart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nank1ro","download_url":"https://codeload.github.com/nank1ro/solidart/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247208142,"owners_count":20901570,"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","signals","solidart","solidjs","state-management"],"created_at":"2024-08-01T12:01:11.543Z","updated_at":"2025-04-04T16:12:02.117Z","avatar_url":"https://github.com/nank1ro.png","language":"Dart","funding_links":["https://github.com/sponsors/nank1ro"],"categories":["Dart"],"sub_categories":[],"readme":"[![License: MIT](https://img.shields.io/badge/license-MIT-purple.svg)](https://opensource.org/licenses/MIT)\n[![GitHub stars](https://img.shields.io/github/stars/nank1ro/solidart)](https://gitHub.com/nank1ro/solidart/stargazers/)\n[![Coverage](https://codecov.io/gh/nank1ro/solidart/branch/main/graph/badge.svg?token=HvJYtaixiW)](https://codecov.io/gh/nank1ro/solidart)\n[![GitHub issues](https://img.shields.io/github/issues/nank1ro/solidart)](https://github.com/nank1ro/solidart/issues/)\n[![GitHub pull-requests](https://img.shields.io/github/issues-pr/nank1ro/solidart.svg)](https://gitHub.com/nank1ro/solidart/pull/)\n[![solidart Pub Version (including pre-releases)](https://img.shields.io/pub/v/solidart?include_prereleases)](https://pub.dev/packages/solidart)\n[![flutter_solidart Pub Version (including pre-releases)](https://img.shields.io/pub/v/flutter_solidart?include_prereleases)](https://pub.dev/packages/flutter_solidart)\n[![All Contributors](https://img.shields.io/github/all-contributors/nank1ro/solidart?color=ee8449\u0026style=flat-square)](#contributors)\n[![](https://dcbadge.vercel.app/api/server/2JBzeeQShh)](https://discord.gg/2JBzeeQShh)\n\n# A simple state-management library inspired by SolidJS.\n\nThe objectives of this project are:\n\n1. Being simple and easy to learn\n2. Fits well with the framework's good practices\n3. Do not have a single global state, but multiple states only in the most appropriate places\n4. No code generation\n\n## Learning\n\nFor a comprehensive and updated documentation go to [The Official Documentation](https://docs.page/nank1ro/solidart)\n\nThere are 5 main concepts you should be aware:\n\n1. [Signals](#signals)\n2. [Effects](#effects)\n3. [Computed](#computed)\n4. [Resources](#resources)\n5. [Solid (only flutter_solidart)](#solid)\n\n### Signals\n\nSignals are the cornerstone of reactivity in _solidart_. They contain values that change over time; when you change a signal's value, it automatically updates anything that uses it.\n\nTo create a signal, you have to use the `Signal` class:\n\n```dart\nfinal counter = Signal(0);\n```\n\nThe argument passed to the class is the initial value, and the return value is the signal.\n\n\nTo retrieve the current value, you can use:\n```dart\nprint(counter.value); // prints 0\n// or\nprint(counter());\n```\n\nTo change the value, you can use:\n```dart\n// Increments by 1\ncounter.value++; \n// Set the value to 2\ncounter.value = 2;\n// equivalent to\ncounter.set(2);\n// Update the value based on the current value\ncounter.updateValue((value) =\u003e value * 2);\n```\n\n### Effects\n\nSignals are trackable values, but they are only one half of the equation. To complement those are observers that can be updated by those trackable values. An effect is one such observer; it runs a side effect that depends on signals.\n\nAn effect can be created by using the `Effect` class.\nThe effect automatically subscribes to any signal and reruns when any of them change.\nSo let's create an Effect that reruns whenever `counter` changes:\n\n```dart\nfinal disposeFn = Effect((_) {\n    print(\"The count is now ${counter.value}\");\n});\n```\n\n### Computed\n\nA computed signal is a signal that depends on other signals.\nTo create a computed signal, you have to use the `Computed` class.\n\nA `Computed` automatically subscribes to any signal provided and reruns when any of them change.\n\n```dart\nfinal name = Signal('John');\nfinal lastName = Signal('Doe');\nfinal fullName = Computed(() =\u003e '${name.value} ${lastName.value}');\nprint(fullName()); // prints \"John Doe\"\n\n// Update the name\nname.set('Jane');\nprint(fullName()); // prints \"Jane Doe\"\n```\n\n### Resources\n\nResources are special Signals designed specifically to handle Async loading. Their purpose is wrap async values in a way that makes them easy to interact with.\n\nResources can be driven by a `source` signal that provides the query to an async data `fetcher` function that returns a `Future`.\n\nThe contents of the `fetcher` function can be anything. You can hit typical REST endpoints or GraphQL or anything that generates a future. Resources are not opinionated on the means of loading the data, only that they are driven by futures.\n\nLet's create a Resource:\n\n```dart\n// The source\nfinal userId = Signal(1);\n\n// The fetcher\nFuture\u003cString\u003e fetchUser() async {\n    final response = await http.get(\n      Uri.parse('https://swapi.dev/api/people/${userId.value}/'),\n    );\n    return response.body;\n}\n\n// The resource\nfinal user = Resource(fetcher: fetchUser, source: userId);\n```\n\nA Resource can also be driven from a [stream] instead of a Future.\nIn this case you just need to pass the `stream` field to the `Resource` class.\n\nIf you're using `ResourceBuilder` you can react to the state of the resource:\n\n```dart\nResourceBuilder(\n  resource: user,\n  builder: (_, userState) {\n    return userState.on(\n      ready: (data) {\n        return Column(\n          mainAxisSize: MainAxisSize.min,\n          children: [\n            ListTile(\n              title: Text(data),\n              subtitle:\n                  Text('refreshing: ${userState.isRefreshing}'),\n            ),\n            userState.isRefreshing\n                ? const CircularProgressIndicator()\n                : ElevatedButton(\n                    onPressed: user.refresh,\n                    child: const Text('Refresh'),\n                  ),\n          ],\n        );\n      },\n      error: (e, _) {\n        return Column(\n          mainAxisSize: MainAxisSize.min,\n          children: [\n            Text(e.toString()),\n            userState.isRefreshing\n                ? const CircularProgressIndicator()\n                : ElevatedButton(\n                    onPressed: user.refresh,\n                    child: const Text('Refresh'),\n                  ),\n          ],\n        );\n      },\n      loading: () {\n        return const RepaintBoundary(\n          child: CircularProgressIndicator(),\n        );\n      },\n    );\n  },\n)\n```\n\nThe `on` method forces you to handle all the states of a Resource (_ready_, _error_ and _loading_).\nThe are also other convenience methods to handle only specific states.\n\n### Solid\n\nThe Flutter framework works like a Tree. There are ancestors and there are descendants.\n\nYou may incur the need to pass a Signal deep into the tree, this is discouraged.\nYou should never pass a signal as a parameter.\n\nTo avoid this there's the _Solid_ widget.\n\nWith this widget you can pass a signal down the tree to anyone who needs it.\n\nYou will have already seen `Theme.of(context)` or `MediaQuery.of(context)`, the procedure is practically the same.\n\nLet's see an example to grasp the concept.\n\nYou're going to see how to build a toggle theme feature using `Solid`, this example is present also here https://github.com/nank1ro/solidart/tree/main/examples/toggle_theme\n\n```dart\nclass MyApp extends StatelessWidget {\n  const MyApp({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    // Provide the theme mode signal to descendats\n    return Solid( // [1]\n      providers: [\n        Provider\u003cSignal\u003cThemeMode\u003e\u003e(\n          create: () =\u003e Signal(ThemeMode.light),\n        ),\n      ],\n      // using the builder method to immediately access the signal\n      builder: (context) {\n        // observe the theme mode value this will rebuild every time the themeMode signal changes.\n        final themeMode = context.observe\u003cThemeMode\u003e(); // [2]\n        return MaterialApp(\n          title: 'Toggle theme',\n          themeMode: themeMode,\n          theme: ThemeData.light(),\n          darkTheme: ThemeData.dark(),\n          home: const MyHomePage(),\n        );\n      },\n    );\n  }\n}\n\nclass MyHomePage extends StatelessWidget {\n  const MyHomePage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    // retrieve the theme mode signal\n    final themeMode = context.get\u003cSignal\u003cThemeMode\u003e\u003e(); // [3]\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text('Toggle theme'),\n      ),\n      body: Center(\n        child:\n            // Listen to the theme mode signal rebuilding only the IconButton\n            SignalBuilder( // [4]\n          signal: themeMode,\n          builder: (_, mode, __) {\n            return IconButton(\n              onPressed: () { // [5]\n                // toggle the theme mode\n                if (themeMode.value == ThemeMode.light) {\n                  themeMode.value = ThemeMode.dark;\n                } else {\n                  themeMode.value = ThemeMode.light;\n                }\n              },\n              icon: Icon(\n                mode == ThemeMode.light ? Icons.dark_mode : Icons.light_mode,\n              ),\n            );\n          },\n        ),\n      ),\n    );\n  }\n}\n```\n\nFirst at `[1]` we've used the `Solid` widget to provide the `themeMode` signal to descendants.\n\nThe `Solid` widgets takes a list of providers:\n The `Provider` has a `create` function that returns the signal.\nYou may create a signal or a derived signal. The value is a Function\nbecause the signal is created lazily only when used for the first time, if\nyou never access the signal it never gets created.\nIn the `Provider` you can also specify an `id`entifier for having multiple\nsignals of the same type.\n\nAt `[2]` we `observe` the value of a signal. The `observe` method listen to the signal value and rebuilds the widget when the value changes. It takes an optional `id` that is the signal identifier that you want to use. This method must be called only inside the `build` method.\n\nAt `[3]` we `get` the signal with the given signal type. This doesn't listen to signal value. You may use this method inside the `initState` and `build` methods.\n\nAt `[4]` using the `SignalBuilder` widget we rebuild the `IconButton` every time the signal value changes.\n\nAnd finally at `[5]` we update the signal value.\n\n\u003e It is mandatory to pass the type of signal value otherwise you're going to encounter an error, for example:\n\n```dart\nProvider\u003cSignal\u003cThemeMode\u003e\u003e(create: () =\u003e Signal(ThemeMode.light))\n```\nand `context.observe\u003cThemeMode\u003e` where ThemeMode is the type of the signal\nvalue.\n`context.get\u003cSignal\u003cThemeMode\u003e\u003e` where `Signal\u003cThemeMode\u003e` is the type\nof signal with its type value.\n\n## DevTools\n\n\u003cimg src=\"https://raw.githubusercontent.com/nank1ro/solidart/main/assets/devtools.png\" width=\"100%\"\u003e\n\nYou can debug your application using the Solidart DevTools extension and filter your signals.\n\n## Examples\n\n### Sample features using flutter_solidart:\n\n- [Counter](https://zapp.run/github/nank1ro/solidart/tree/main/examples/counter)\n- [Toggle theme (dark/light mode)](https://zapp.run/github/nank1ro/solidart/tree/main/examples/toggle_theme)\n- [Todos](https://zapp.run/github/nank1ro/solidart/tree/main/examples/todos)\n- [Github Search](https://zapp.run/github/nank1ro/solidart/tree/main/examples/github_search)\n\n### Showcase of all flutter_solidart features\n\n- [Showcase of all features](https://zapp.run/github/nank1ro/solidart/tree/main/packages/flutter_solidart/example)\n\nLearn every feature of `flutter_solidart` including:\n\n1. `Signal`\n2. `Show` widget\n3. `Computed`\n4. `Effect`s\n5. `SignalBuilder`, `DualSignalBuilder` and `TripleSignalBuilder`\n6. `Resource` and `ResourceBuilder`\n7. `Solid` and its fine-grained reactivity\n\n## Contributors\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://www.bestofcode.dev\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/60045235?v=4?s=100\" width=\"100px;\" alt=\"Alexandru Mariuti\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eAlexandru Mariuti\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nank1ro/solidart/commits?author=nank1ro\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/nank1ro/solidart/issues?q=author%3Anank1ro\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"#maintenance-nank1ro\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e \u003ca href=\"#question-nank1ro\" title=\"Answering Questions\"\u003e💬\u003c/a\u003e \u003ca href=\"https://github.com/nank1ro/solidart/pulls?q=is%3Apr+reviewed-by%3Anank1ro\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e \u003ca href=\"https://github.com/nank1ro/solidart/commits?author=nank1ro\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"https://github.com/nank1ro/solidart/commits?author=nank1ro\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/manuel-plavsic\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/55398763?v=4?s=100\" width=\"100px;\" alt=\"manuel-plavsic\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003emanuel-plavsic\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nank1ro/solidart/commits?author=manuel-plavsic\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/luketg8\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/10770936?v=4?s=100\" width=\"100px;\" alt=\"Luke Greenwood\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eLuke Greenwood\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nank1ro/solidart/commits?author=luketg8\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/9dan\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/32853831?v=4?s=100\" width=\"100px;\" alt=\"9dan\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003e9dan\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/nank1ro/solidart/commits?author=9dan\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/nank1ro/solidart/issues?q=author%3A9dan\" title=\"Bug reports\"\u003e🐛\u003c/a\u003e \u003ca href=\"https://github.com/nank1ro/solidart/commits?author=9dan\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnank1ro%2Fsolidart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnank1ro%2Fsolidart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnank1ro%2Fsolidart/lists"}