Skip to content

Observable store

Classes

ObservableStoreObservable

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

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

// Create a store with default localStorage support
const CartStore = store({ cartItems: [] });

// Create a store without localStorage support
const NonPersistentStore = store({ items: [] }, { localStorage: false });