Security News
Weekly Downloads Now Available in npm Package Search Results
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
@betomorrow/micro-stores
Advanced tools
A light state management library featuring observables and immutability
A light state management library featuring observables and immutability
import { Store } from "micro-stores";
const bookStore = new Store((id) => fetch(`https://myApi.com/books/${id}`));
const myFavoriteBook = bookStore.getObservable("dracula");
console.log(myFavoriteBook.get()); // null
bookStore.fetch("dracula");
console.log(myFavoriteBook.get()); // { id: "Dracula", ... }
This library depends on uuid. To use uuid, and therefore micro-stores with React Native, you need to follow the steps described at https://github.com/uuidjs/uuid#react-native--expo:
pod install
import 'react-native-get-random-values';
This library is quite heavily based on micro-observables. You may want to take a look at the Observable
signature there.
Micro-stores exposes 3 main Stores that can be used to easily manage your application state.
A simple Store retrieving items using a primary key.
import { Store } from "micro-stores";
const bookStore = new Store((id) => fetchBook(id));
bookStore.fetch();
To create a Store, you have to provide a fetcher function retrieving objects using an unique identifier. By default, your store will use the id
property of the object (if it exists).
If your object doesn't have an id
property, you will need to use one, or specify another unique property to be used.
Constructor parameters
Parameter | Type | Default Value | Description |
---|---|---|---|
fetch | (key: string) => T | Promise<T> | / | The function retrieving item by its key |
primaryKey | string | "id" | The primary key to use to map your objects |
Builder Methods
bindProperty
You can enrich your Store by binding a property to another Store using the bindProperty
method.
This is useful if you want to ensure yours objects are up to date when making changes to its referenced property. The Store will use the referenced property unless it is removed from its own Store
Usage
import { Store } from "micro-stores";
const userStore = new Store(fetchUser);
const bookStore = new Store(fetchBook).bindProperty("infos.author", userStore);
bookStore.fetch("dracula");
console.log(userStore.getObservable("bram-staker").get());
// { id: bram-stoker, name: "Bram Stoker" }
userStore.save({ id: "bram-staker", name: "Bram" });
console.log(bookStore.getObservable("dracula").get().infos.author);
// { id: "bram-staker", name: "Bram" }
userStore.remove("bram-staker");
console.log(bookStore.getObservable("dracula").get().infos.author);
// { id: "bram-staker", name: "Bram Staker" }
presentProperty
It has the same purpose as bindProperty, but can be used with lighter objects. This means that when fetching items from your store, it will not populate the presented Store with light values. However, it will update the presented store with updated value if they already exist.
Method | Type | Description |
---|---|---|
bindProperty | (path: string, referenceStore: Store<U>) => Store<T> | Binds your item property to another Store |
presentProperty | (path: string, referenceStore: Store<Partial<U>>) => Store<T> | Presents your item property to another Store |
Methods and properties
Main methods and properties:
Property | Type | Description |
---|---|---|
primaryKey | string | The primary key to use to map your objects |
items | Observable<Map<string, T>> | The observable of the items mapped by their key |
getObservable | (key: string) => Observable<T> | Retrieve an observable using its key |
fetch | (key: string) => Promise | Call the Store fetch function and saves the received item |
save | (item: T) => void | Save an item to the Store. If an items exists will the same key, it will be erased |
merge | (items: T[]) => void | Save several items at once |
remove | (key: string) => void | Remove an item from the Store |
update | (key: string, updater: (current: T) => T) => void | Update an item using an update callback, if it exists |
updateProperties | (item: Partial) => void | Update an items with specified properties, if it exists |
batchUpdateProperties | (items: Partial[]) => void | Update several items with specific properties, if they exists |
clear | () => void | Clears the store |
onDelete | Signal | Called when an item is removed from the Store |
A PaginatedStore stores items in an Array and handles pagination for you using Pages.
import { PaginatedStore } from "micro-stores";
const bookStore = new PaginatedStore((page) => fetchBooks(page));
bookStore.list();
bookStore.listMore();
bookStore.listMore();
To create a PaginatedStore, you have to provide a fetcher function retrieving a page of objects using an page number.
A Page is an interface defined by this properties:
interface Page {
content: T[];
page: number;
totalPages: number;
totalSize: number;
}
Constructor parameters
Parameter | Type | Description |
---|---|---|
fetchList | (page: number) => Promise<Page> | Page) | The function retrieving Page by its index |
Builder Methods
bind
You can bind your PaginatedStore to another Store using the bind
method.
This will allow you to show in your list of items the actual items from the binded Store, thus ensuring them to be up to date. The binded Store will also be automatically updated with the values retrieved when listing objects from the PaginatedStore
You can only bind a PaginatedStore to a Store that stores the exact same interface of objects. Meaning that your PaginatedStore will have to use the same unique identifier property as your simple Store.
You can only bind your PaginatedStore to a single Store.
Usage
import { Store, PaginatedStore } from "micro-stores";
const bookStore = new Store(fetchBook);
const favoriteBookStore = new PaginatedStore(fetchBook).bind(bookStore);
favoriteBookStore.list();
console.log(bookStore.getObservable("dracula").get());
// { id: "dracula", name: "Dracula" }
bookStore.save({ id: "dracula", name: "Dracula 2" });
console.log(favoriteBookStore.paginatedItems.get().content[0]);
// { id: "dracula", name: "Dracula 2" }
bookStore.remove("dracula");
console.log(favoriteBookStore.paginatedItems.get().content[0]);
// null
present
present
is very similar to the bind
building method. The difference being it allows you to present from a Store items that are partials objects stored in a PaginatedStore.
For performance purpose, prefer using bind
over present
if your Store and your PaginatedStore use the exact same objects.
Your can only bind
or present
one single Store
Method | Type | Description |
---|---|---|
bind | (referenceStore: Store<T>) => Store<T> | Binds your Paginated Store to another Store |
present | (referenceStore: Store<U extends T>) => Store<T> | Binds your Paginated Store to another Store |
Methods and properties
Main methods and properties:
Property | Type | Description |
---|---|---|
fetching | Observable<boolean> | Is the store fetching initial items ? |
fetchingMore | Observable<boolean> | Is the store fetching more items ? |
paginatedItems | Observable<Page<T> | null> | The observable page of the items |
list | () => void | Call the Store fetchList function for the first page and erases the existing items |
listMore | () => void | Call the Store fetchList function and merge the new items |
A MappedStore stores paginated arrays of items in an Map.
It is quite similar to PaginatedStore, also allowing you to store your paginated items according to specified keys.
import { MappedStore } from "micro-stores";
const bookStore = new MappedStore((userId, page) => fetchFavoriteBooksForUser(userId, page));
bookStore.list("user-1");
bookStore.listMore("user-1");
bookStore.list("user-2");
To create a MappedStore, you have to provide a fetcher function retrieving a page of objects using a mapping key and page number.
Constructor parameters
Parameter | Type | Description |
---|---|---|
fetchList | (id: string, page: number) => Promise<Page> | Page) | The function retrieving Page by its index |
Builder Methods
bind and present
Just like a PaginatedStore, a MappedStore allows you to bind/present another Store.
Methods and properties
Main methods and properties:
Property | Type | Description |
---|---|---|
getFetching | (key:string) => Observable<boolean> | Is the store fetching initial items for this key? |
getFetchingMore | (key:string) => Observable<boolean> | Is the store fetching more items for this key? |
getObservableItems | (key:string) => Observable<Page<T> | null> | The observable page of the items |
list | (key: string) => void | Call the Store fetchList function for this key for the first page and erases the existing items |
listMore | (key: string) => void | Call the Store fetchList function for this key and merge the new items |
clear | () => void | Clears the store |
This library makes State Management easier for any nodeJS or browser application, and has been especially thought to be used with React.
This is why Micro-stores also gives you hooks to help you manage and retrieve the state of your React project:
Return the value of the matching the given key, the loading state and the current error. Triggers a re-render when the value changes.
import { Store, useStore } from "micro-stores";
const bookStore = new Store(fetchBook);
const DraculaBookView = () => {
const { result: book, loading, error } = useStore("dracula", bookStore);
if (book) {
return (
<div>
{book.title} from {book.author}
</div>
);
}
if (loading) {
return <div>Loading...</div>;
}
return null;
};
Returns a PaginatedDataResult
of the given paginated store. Triggers a rerender when these properties change.
import { PaginatedStore, usePaginatedStore } from "micro-stores";
const bookStore = new PaginatedStore(fetchBooks);
const BookView = () => {
const { result: books, listMore, lastPage, loading, moreLoading } = usePaginatedStore(bookStore);
if (loading) {
return <div>Loading...</div>;
}
return <div>
<h2>Books</h2>
{books.map(book => <BookView book={book}/>}
{moreLoading && <div>Loading...</div>}
{!lastPage && <button onClick={() => listMore()}>Load More</button>}
</div>
};
Similar to usePaginatedStore
, only difference being you need to pass in the key you want to fetch.
PaginatedDataResult
The PaginatedDataResult is defined like this:
Property | Type | Description |
---|---|---|
result | T[] | The current array of results |
loading | boolean | Is the first page being loaded |
moreLoading | boolean | Are more items beeing loaded |
error | Error |null | Fetching error |
lastPage | boolean | Are all the pages fetched |
totalPages? | number | undefined | The number of pages |
totalSize? | number | undefined | The total size of the elements |
list | () => void | Function to fetch the first page |
listMore | () => void | Function to fetch the next page |
clear | () => void | Clears the store |
The hooks above allow you to define a Fetch Strategy to decide how often the data should be fetch:
This library is entirely written in Typescript, meaning you can benefit from its typings without installing other packages.
FAQs
A light state management library featuring observables and immutability
The npm package @betomorrow/micro-stores receives a total of 70 weekly downloads. As such, @betomorrow/micro-stores popularity was classified as not popular.
We found that @betomorrow/micro-stores demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 6 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.
Security News
A Stanford study reveals 9.5% of engineers contribute almost nothing, costing tech $90B annually, with remote work fueling the rise of "ghost engineers."
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.