Observable store
Classes
- ObservableStore ⇐
Observable
Functions
- slice(store, options) ⇒
Object
Creates a slice of the store with its own state and actions, namespaced to avoid conflicts.
- store(initialState, [options]) ⇒
ObservableStore
This function creates a new instance of ObservableStore with the provided initial state and enhances it with localStorage support if enabled. The store's state will be automatically persisted to and loaded from localStorage, using the provided name as the key. The
localStorage
option enables this behavior and can be toggled off if persistence is not needed.
ObservableStore ⇐ Observable
Kind: global class
Extends: Observable
- ObservableStore ⇐
Observable
new ObservableStore()
This class is used to create a store that can be observed for changes. It supports registering actions and middleware, making it flexible for various use cases.
Example
// Creating a store with initial state and registering actions
const CartStore = cami.store({
cartItems: [],
});
CartStore.register('add', (state, product) => {
const cartItem = { ...product, cartItemId: Date.now() };
state.cartItems.push(cartItem);
});
CartStore.register('remove', (state, product) => {
state.cartItems = state.cartItems.filter(item => item.cartItemId !== product.cartItemId);
});
// Using middleware for logging
const loggerMiddleware = (context) => {
console.log(`Action ${context.action} was dispatched with payload:`, context.payload);
};
CartStore.use(loggerMiddleware);
ObservableStore.use(middleware)
This method registers a middleware function to be used with the store. Useful if you like redux-style middleware.
Kind: static method of ObservableStore
Param | Type | Description |
---|---|---|
middleware | function |
The middleware function to use |
Example
const loggerMiddleware = (context) => {
console.log(`Action ${context.action} was dispatched with payload:`, context.payload);
};
CartStore.use(loggerMiddleware);
ObservableStore.getState() ⇒ Object
Retrieves the current state of the store. This method is crucial in asynchronous operations or event-driven environments to ensure the most current state is accessed, as the state might change frequently due to user interactions or other asynchronous updates.
Kind: static method of ObservableStore
Returns: Object
- - The current state of the store.
ObservableStore.register(action, reducer)
This method registers a reducer function for a given action type. Useful if you like redux-style reducers.
Kind: static method of ObservableStore
Throws:
Error
- Throws an error if the action type is already registered
Param | Type | Description |
---|---|---|
action | string |
The action type |
reducer | function |
The reducer function for the action |
Example
// Creating a store with initial state and registering actions
const CartStore = cami.store({
cartItems: [],
});
CartStore.register('add', (state, product) => {
const cartItem = { ...product, cartItemId: Date.now() };
state.cartItems.push(cartItem);
});
CartStore.register('remove', (state, product) => {
state.cartItems = state.cartItems.filter(item => item.cartItemId !== product.cartItemId);
});
ObservableStore.query(queryName, config)
Registers an asynchronous query with the specified configuration.
Kind: static method of ObservableStore
Param | Type | Default | Description |
---|---|---|---|
queryName | string |
The name of the query. | |
config | Object |
The configuration object for the query, containing the following properties: | |
config.queryKey | string |
The unique key for the query. | |
config.queryFn | function |
The asynchronous query function that returns a promise. | |
[config.staleTime] | number |
0 |
Optional. The time in milliseconds after which the query is considered stale. Defaults to 0. |
[config.refetchOnWindowFocus] | boolean |
true |
Optional. Whether to refetch the query when the window regains focus. Defaults to true. |
[config.refetchOnReconnect] | boolean |
true |
Optional. Whether to refetch the query when the network reconnects. Defaults to true. |
[config.refetchInterval] | number | null |
|
Optional. The interval in milliseconds at which to refetch the query. Defaults to null. |
[config.gcTime] | number |
300000 |
Optional. The time in milliseconds after which the query is garbage collected. Defaults to 300000 (5 minutes). |
[config.retry] | number |
3 |
Optional. The number of times to retry the query on error. Defaults to 3. |
[config.retryDelay] | function |
(attempt) => Math.pow(2, attempt) * 1000 |
Optional. A function that returns the delay in milliseconds for each retry attempt. Defaults to a function that calculates an exponential backoff based on the attempt number. |
Example
// Register a query to fetch posts
appStore.query('posts/fetchAll', {
queryKey: 'posts/fetchAll',
queryFn: () => fetch('https://api.camijs.com/posts').then(res => res.json()),
refetchOnWindowFocus: true,
});
// Register actions for pending, success, and error states of the query
appStore.register('posts/fetchAll/pending', (state, payload) => {
state.isLoading = true;
state.posts = [];
state.error = null;
});
appStore.register('posts/fetchAll/success', (state, payload) => {
state.posts = payload;
state.isLoading = false;
state.error = null;
});
appStore.register('posts/fetchAll/error', (state, payload) => {
state.error = payload;
state.isLoading = false;
state.posts = [];
});
// Fetch all posts
appStore.fetch('posts/fetchAll');
// Subscribe to updates
appStore.subscribe(newState => {
console.log('New state:', newState);
});
ObservableStore.fetch(queryName, ...args) ⇒ Promise.<any>
Fetches data for a given query name, utilizing cache if available and not stale. If data is stale or not in cache, it fetches new data using the query function.
Kind: static method of ObservableStore
Returns: Promise.<any>
- A promise that resolves with the fetched data.
Param | Type | Description |
---|---|---|
queryName | string |
The name of the query to fetch data for. |
...args | any |
Arguments to pass to the query function. |
Example
// Register a query to fetch posts
appStore.query('posts/fetchAll', {
queryKey: 'posts/fetchAll',
queryFn: () => fetch('https://api.camijs.com/posts').then(res => res.json()),
refetchOnWindowFocus: true,
});
// Register actions for pending, success, and error states of the query
appStore.register('posts/fetchAll/pending', (state, payload) => {
state.isLoading = true;
state.posts = [];
state.error = null;
});
appStore.register('posts/fetchAll/success', (state, payload) => {
state.posts = payload;
state.isLoading = false;
state.error = null;
});
appStore.register('posts/fetchAll/error', (state, payload) => {
state.error = payload;
state.isLoading = false;
state.posts = [];
});
// Fetch all posts
appStore.fetch('posts/fetchAll');
// Subscribe to updates
appStore.subscribe(newState => {
console.log('New state:', newState);
});
ObservableStore.invalidateQueries(queryName)
Invalidates the cache and any associated intervals or event listeners for a given query name.
Kind: static method of ObservableStore
Param | Type | Description |
---|---|---|
queryName | string |
The name of the query to invalidate. |
ObservableStore.dispatch(action, payload)
Use this method to dispatch redux-style actions or flux actions, triggering state updates.
Kind: static method of ObservableStore
Throws:
Error
If the action type is not a string when expected.
Param | Type | Description |
---|---|---|
action | string | function |
The action type as a string or a function that performs custom dispatch logic. |
payload | Object |
The data to be passed along with the action. |
Example
// Dispatching an action with a payload
CartStore.dispatch('add', { id: 1, name: 'Product 1', quantity: 2 });
slice(store, options) ⇒ Object
Creates a slice of the store with its own state and actions, namespaced to avoid conflicts.
Kind: global function
Returns: Object
- - An object containing the action methods for the slice, including getState, actions, and subscribe methods.
Param | Type | Description |
---|---|---|
store | Object |
The main store instance. |
options | Object |
The options for creating the slice. |
options.name | string |
The name of the slice. |
options.state | Object |
The initial state of the slice. |
options.actions | Object |
The actions for the slice. |
Example
const cartSlice = slice(appStore, {
name: 'cart',
state: {
cartItems: [],
},
actions: {
add(state, product) {
const newItem = { ...product, id: Date.now() };
state.cartItems.push(newItem);
},
remove(state, product) {
state.cartItems = state.cartItems.filter(item => item.id !== product.id);
},
}
});
// Dispatching actions
cartSlice.actions.add({ name: 'Product 1', price: 100 });
cartSlice.actions.remove({ id: 123456789 });
// Getting the current state
console.log(cartSlice.getState()); // Logs the current state of the cart slice
// Subscribing to state changes
const unsubscribe = cartSlice.subscribe(newState => {
console.log('Cart slice state changed:', newState);
});
// Unsubscribe when no longer needed
unsubscribe();
store(initialState, [options]) ⇒ ObservableStore
This function creates a new instance of ObservableStore with the provided initial state and enhances it with localStorage support if enabled. The store's state will be automatically persisted to and loaded from localStorage, using the provided name as the key. The localStorage
option enables this behavior and can be toggled off if persistence is not needed.
Kind: global function
Returns: ObservableStore
- A new instance of ObservableStore with the provided initial state, enhanced with localStorage if enabled.
Param | Type | Default | Description |
---|---|---|---|
initialState | Object |
The initial state of the store. | |
[options] | Object |
Configuration options for the store. | |
[options.localStorage] | boolean |
true |
Whether to use localStorage for state persistence. |
[options.name] | string |
"'cami-store'" |
The name of the store to use as the key in localStorage. |
[options.expiry] | number |
86400000 |
The time in milliseconds until the stored state expires (default is 24 hours). |
Example