Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/zuriscript/signalstory
Signal-based state management for Angular applications
https://github.com/zuriscript/signalstory
Last synced: 23 days ago
JSON representation
Signal-based state management for Angular applications
- Host: GitHub
- URL: https://github.com/zuriscript/signalstory
- Owner: zuriscript
- License: mit
- Created: 2023-07-18T23:13:56.000Z (over 1 year ago)
- Default Branch: master
- Last Pushed: 2024-06-16T21:40:17.000Z (6 months ago)
- Last Synced: 2024-11-08T11:13:59.466Z (about 1 month ago)
- Language: TypeScript
- Homepage: https://zuriscript.github.io/signalstory/
- Size: 17 MB
- Stars: 41
- Watchers: 0
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.md
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
- awesome-angular - signalstory - A state management library based on Angular signals. It offers a range of architectural options, from simple repository-based state management (signal-in-a-service) to orchestrating decoupled commands, handling side effects through encapsulated objects, and facilitating inter-store communication using an event-driven approach. (Table of contents / Third Party Components)
- fucking-awesome-angular - signalstory - A state management library based on Angular signals. It offers a range of architectural options, from simple repository-based state management (signal-in-a-service) to orchestrating decoupled commands, handling side effects through encapsulated objects, and facilitating inter-store communication using an event-driven approach. (Table of contents / Third Party Components)
- fucking-awesome-angular - signalstory - A state management library based on Angular signals. It offers a range of architectural options, from simple repository-based state management (signal-in-a-service) to orchestrating decoupled commands, handling side effects through encapsulated objects, and facilitating inter-store communication using an event-driven approach. (Table of contents / Third Party Components)
- fucking-awesome-angular - signalstory - A state management library based on Angular signals. It offers a range of architectural options, from simple repository-based state management (signal-in-a-service) to orchestrating decoupled commands, handling side effects through encapsulated objects, and facilitating inter-store communication using an event-driven approach. (Table of contents / Third Party Components)
README
Signalstory - Angular state management with signals
Baked into classical angular services!
Documentation 📚
Sample 🚀
Website 🔥
Release notes ✨[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![npm version](https://badge.fury.io/js/signalstory.svg)](https://badge.fury.io/js/signalstory)
[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
[![PRs](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)]()
[![coc-badge](https://img.shields.io/badge/codeof-conduct-ff69b4.svg?style=flat-square)]()
[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)signalstory is a state management library based on angular signals. It offers a range of architectural options, from simple repository-based state management (`signal-in-a-service`) to orchestrating decoupled commands, handling side effects through encapsulated objects, and facilitating inter-store communication using an event-driven approach. The ultimate goal is to provide a great user experience for all developers, whether junior or senior, while incorporating all the features you need to master your frontend state requirements.
> [!TIP]
> Starting out? You can keep it nice and simple if you prefer to avoid exploring all the advanced features that a state management library can offer! Begin by checking out the [store](https://zuriscript.github.io/signalstory/docs/store), and only dive into the rest if you're curious later on.Here's a snapshot of some notable highlights:
✅ Signal-in-a-service approach
✅ Simple, non-intrusive and lightweight
✅ Optimized for Scalability
✅ Imperative-first with Declaritive capabilities
✅ Immutability on demand
✅ Rich plugin ecosystem
✅ Native IndexedDB support
✅ Transactional Undo/Redo
✅ Global State Snaphots and Rollbacks
✅ Devtools support
✅ Effect and Store status tracking
✅ Realtime store performance statistics
✅ Custom plugin support
✅ Built-in testing utilities
✅ SSR friendly
✅ Tree-shakeable## Let the store grow with your project
## Guiding Principles
- 🚀 Use class methods to provide controlled access and mutations to shared state.
- 🌌 If your store becomes too complex and bloated, slice it into multiple stores.
- ✨ Join and aggregate your state at the component level using signal mechanics.
- 🌐 Need to sync states between stores synchronously? - Use events.
- 🔮 Need to decouple actors and consumers as you do in `redux`? - Use events.
- 🔄 Craving `Immutability`? - Just activate it.
- 🏎️ Don't want full immutability because your store has to be super fast? - Don't activate it.
- 🧙♂️ Seeking a way to encapsulate side effects in a reusable, maintainable, and testable way? - Use effect objects.
- 🔍 Want a way to reuse and test queries spanning over multiple stores? - Use query objects.
- 📦 Don't want to use a class for stores? - You don't have to.
- 🛠️ Tired of debugging state changes in the console? - Enable redux devtools.
- 🪄 Still want some good old logging magic? - Enable Store logger plugin
- ⏳ Need to keep track of store history and perform undo/redo operations? - track the history.
- 💾 Want to sync your state with local storage? - Enable the persistence plugin.
- 🗄️ Need a more sophisticated store storage or building an offline app? - Use IndexedDB adapter
- 📈 Need to get notified of whether your store is modified or currently loading? - Enable the Store Status plugin.
- 📊 Wondering where your bottlenecks are? - Enable the performance counter plugin
- 🎨 Something's missing? - Write a custom plugin.
- 📖 Read the [docs](https://zuriscript.github.io/signalstory/) for more features and concepts.## Installation
Install the library using npm:
```shell
npm install signalstory
```## Sneak peek
```typescript
import { produce } from 'immer';// Immutable store class using immer.js for boosting immutable mutations
@Injectable({ providedIn: 'root' })
class BookStore extends ImmutableStore {
constructor() {
super({
initialState: { ... },
name: 'Books Store',
mutationProducerFn: produce,
plugins: [
useDevtools(),
usePerformanceCounter(),
useLogger(),
useStoreStatus(),
useStorePersistence(
configureIndexedDb({
dbName: 'SharedDatabase',
})),
],
});
// Handle store reset request events. Note, the storeResetRequestEvent would
// be created or imported, see the events documentation for more details
this.registerHandler(storeResetRequestEvent, store => {
store.set([], 'Reset');
});
}// Query
public get getBooksInCollection() {
return computed(() => this.state().filter(x => x.isInCollection));
}// Command
public addToCollection(bookId: string) {
this.mutate(state => {
const book = state.find(x => x.id === bookId);
if (book) {
book.isInCollection = true;
}
}, 'Add Book To Collection');
}
}
``````typescript
// Encapsulated multi store query object
export const BooksAndPublishersByAuthorInSwitzerlandQuery = createQuery(
[BookStore, PublisherStore],
(books, publishers, authorId: string) => {
const booksFromAuthor = books.state().filter(x => x.author === authorId);
const publishersInSwitzerland = publishers
.state()
.filter(x => x.country === 'CH');return booksFromAuthor.map(book => ({
book,
publisher: publishersInSwitzerland.find(
p => p.id === book.mainPublisherId
),
}));
}
);
// And then run it
const query = myBookStore.runQuery(
BooksAndPublishersByAuthorInSwitzerlandQuery,
'sapowski'
);
``````typescript
// Encapsulated effect object
export const fetchBooksEffect = createEffect(
'Fetch Books',
(store: BookStore) => {
const service = inject(BooksService);
const notification = inject(NotificationService);return service.fetchBooks().pipe(
catchError(err => {
notification.alertError(err);
return of([]);
}),
tap(result => store.setBooks(result))
);
},
{
setLoadingStatus: true, // indicates that the store is loading while the effect runs
setInitializedStatus: true, // it should mark the store as initialized upon completion
}
);
// And then run it
myBookStore.runEffect(fetchBooksEffect).subscribe();
const loadingSignal = isLoading(myBookStore); // true while effect is running
const initializedSignal = initialized(myBookStore); // true after initializing effect completion
const modifiedSignal = modified(myBookStore); // true after store update
``````typescript
// Track history spanning multiple stores
const tracker = trackHistory(50, store1, store2);// Undo single commands
store1.set({ value: 10 }, 'ChangeCommand');
tracker.undo();tracker.beginTransaction('Transaction Label');
store1.set({ value: 42 }, 'ChangeCommand');
store2.set({ value: 23 }, 'AnotherCommand');
tracker.endTransaction();// Undo both commands on store1 and store2 at once
tracker.undo();// Redo the whole transaction
tracker.redo();
```## Sample Application
To set up and run the sample app locally, follow the steps below:
1. **Clone the repository:** Clone the repository containing the signalstory library and the sample app.
2. **Install dependencies:** Navigate to the root directory of the repository and run the following command to install the necessary dependencies:
```bash
npm install
```3. **Build the library:** Run the following command to build the signalstory library:
```bash
ng build signalstory
```4. **Serve the sample app:** Run the following command to serve the sample app locally:
```bash
ng serve sample --open
```---
made with ❤️ by zuriscript