{"id":"grilme99/signals","name":"signals","scope":"grilme99","platform":"roblox","description":"Scalable and minimal reactive programming framework for Luau.","version":"0.9.1","latest":"0.9.1","versions":["0.9.1"],"license":"MIT","licenseRating":"safe","licenseCaveats":[],"licenseVerified":true,"dependencies":{"roblox/react":{"version":"^17.3.11","alias":"React"}},"integrity":"4ea02cfed71e72076856f8d06baad371aa2bfabb0d2294baa9daa96db2053151","likes":0,"downloads":0,"install":"forest install grilme99/signals","url":"https://forest.dev/p/roblox/grilme99/signals","files":"https://api.forest.dev/ai/package/roblox/grilme99/signals/files","readme":"# signals\n\n[![ci](https://github.com/Roblox/signals/actions/workflows/ci.yml/badge.svg)](https://github.com/Roblox/signals/actions/workflows/ci.yml)\n[![Get it on Creator Store](./.github/assets/link-creator-store.svg)](https://create.roblox.com/store/asset/71408264115531/Signals)\n[![Contributions welcome](./.github/assets/link-contributions.svg)](CONTRIBUTING.md)\n[![Wally (external link)](./.github/assets/link-wally.svg)](https://wally.run/package/roblox/signals)\n\nScalable and minimal reactive programming framework for [Luau](https://luau.org/).\n\n## Overview\n\nSignals provides fine-grained reactivity through a minimal set of primitives that automatically track dependencies and efficiently propagate updates. It enables building reactive systems where only the necessary computations re-run when data changes.\n\n## Motivation\n\nThose with limited experience in reactive programming may find [this article](https://dev.to/ryansolid/a-hands-on-introduction-to-fine-grained-reactivity-3ndf) helpful as a pre-read.\n\nThe initial motivation for this library originated with the desire for a performant state management solution. In particular, we sought to move from a global \"Redux-like\" state towards a distributed \"fine-grained\" state graph.\n\n## Usage\n\nThe core API is very minimal, consisting of three core primitives:\n\n### `createSignal`\n\n```luau\ncreateSignal<T>(initial: (() -> T) | T, equals: equals<T>?): (getter<T>, setter<T>)\n```\n\nCreates a queryable and settable value.\n\n* Lazy-initializable with a constructor\n* Cacheable with an optional `equals` parameter\n* The getter can be provided a `scope` for automatic dependency tracking (see [createComputed](#createComputed) and [createEffect](#createEffect))\n\n```luau\nlocal getFirstName, setFirstName = createSignal(\"David\")\nlocal getLastName, setLastName = createSignal(\"Tennant\")\n\nprint(getFirstName(false)) -- prints: David\n\nsetFirstName(\"The\")\nsetLastName(\"Doctor\")\n\nprint(`{getFirstName(false)} {getLastName(false)}`) -- prints: The Doctor\n```\n\n### `createComputed`\n\n```luau\ncreateComputed<T>(computed: (scope) -> T, equals: equals<T>?): getter<T>\n```\n\nCreates a read-only reactive derived value.\n\n* Lazy evaluation (computed updates when value is read)\n* Can be used to define \"derived\" state using signals and other computeds\n* The `scope` can be used to automatically and reactively track updates to dependencies\n\n```luau\nlocal getFullName = createComputed(function(scope)\n    return `{getFirstName(scope)} {getLastName(scope)}`\nend)\n\nprint(getFullName(false)) -- prints: The Doctor\n```\n\n### `createEffect`\n\n```luau\ncreateEffect(effect: (scope) -> ()): dispose\n```\n\nCreates a reactive side effect.\n\n* Eager evaluation\n* The `scope` can be used to automatically and reactively track updates to dependencies\n\n```luau\nlocal dispose = createEffect(function(scope)\n    print(`Their real name is {getFullName(scope)}`)\nend)\n-- prints: Their real name is The Doctor\n\nbatch(function()\n    setFirstName(\"David\")\n    setLastName(\"Tennant\")\nend)\n-- prints: Their real name is David Tennant\n\ndispose()\n```\n\n> [!WARNING]\n> You MUST store a strong reference to the `dispose` function returned from `createEffect` for the effect to be guaranteed to re-run. Not storing a strong reference to this function means the effect is liable to be garbage collected.\n\n## Implementation\n\nThe reactive graph uses a pull-based lazy evaluation model with automatic dependency tracking via the `scope` mechanism. When a getter is called with a `scope`, the source registers itself with the observing computed or effect. Updates propagate through the graph and are coalesced via the scheduler to avoid redundant recomputation.\n\nFor more detail on the algorithms, see:\n- [Reactive Algorithms](https://github.com/milomg/reactively/blob/main/Reactive-algorithms.md) (Reactively)\n- [Monotonic Painting](https://fluff.blog/2024/04/16/monotonic-painting.html)\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, coding standards, and how to submit changes.\n\n## Acknowledgements\n\nThis library builds upon the existing work on [reactive programming](https://en.wikipedia.org/wiki/Reactive_programming), particularly drawing inspiration from [S.js](https://github.com/adamhaile/S), [Reactively](https://github.com/milomg/reactively), [Fusion](https://github.com/dphfox/Fusion), and [jotai](https://github.com/pmndrs/jotai).\n\n## License\n\nThis project is licensed under the terms of the [MIT license](LICENSE).\n","readmeTruncated":false}