UNPKG

zippy-store

Version:

A lightweight and versatile global state management solution designed for seamless integration in both JavaScript and React applications. Provides a simple and efficient way to manage shared state across components and even in non-React JavaScript environ

277 lines (210 loc) 8.29 kB
# zippy-store [![npm version](https://badge.fury.io/js/zippy-store.svg)](https://badge.fury.io/js/zippy-store) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) **zippy-store** is a lightweight, flexible, and type-safe global shared state management library for React, React Native, and JavaScript applications. It provides a simple API to manage global shared state, subscribe to state changes, and dispatch actions. With built-in support for selector, it ensures optimal performance by preventing unnecessary re-renders. Additionally, it includes seamless persistence, ensuring state is retained across sessions. --- ## Features - 🚀 **Lightweight**: Minimalistic API with zero dependencies. - 🛠 **Type-Safe**: Built with TypeScript for better developer experience. - 🎯 **Selector**: Extract specific parts of the state to avoid unnecessary re-renders. - 🔄 **Reactive**: Automatically re-renders components when the state changes. - 🧩 **Modular**: Create multiple stores for different parts of your application. - 📦 **Persistence**: Built-in persistence support for JavaScript, React and React Native(AsyncStorage) apps. - 🔗 **Shared State**: Share and sync state across multiple components seamlessly. - 📊 **Global Access**: Access and update state globally from any component. - 📤 **State Synchronization**: Ensure consistent data flow between different UI sections. - ⚡️ **Async Support**: Handle asynchronous state updates effortlessly. --- ## Installation You can install **zippy-store** via npm: ```bash npm install zippy-store ``` or ```bash yarn add zippy-store ``` ## Usage ### Creating a Store in React and React Native You can create a store using the `create` function and use it in components. ```ts import { create } from "zippy-store"; const useCounterTimerStore = create("counterTimerStore", (set, get) => ({ //set for setting the state and get for getting the state counter: 0, timer: 60, user: { name: "John Doe", age: 30 }, incrementCounter: () => set((state) => ({ counter: state.counter + 1 })), // return the new state in set function with callback decrementTimer: () => { const { timer } = get(); // get the current value of timer return set({ timer: timer - 1 }); //can also pass object in set directly }, })); export default useCounterTimerStore; ``` #### Example 1: Using Full State ```tsx import React from "react"; import useCounterTimerStore from "./useCounterTimerStore"; const Example_1 = () => { const { counter, timer, dispatch } = useCounterTimerStore(); return ( <div> <h4>Example_1</h4> <h2>Counter Value : {counter}</h2> <h2>Timer Value: {timer}</h2> <div> <button onClick={dispatch.incrementCounter}>Increment Counter</button> <button style={{ marginLeft: 10 }} onClick={dispatch.decrementTimer}> Decrement Timer </button> </div> </div> ); }; export default Example_1; ``` #### Example 2: Using Selector to Optimize Re-renders ```tsx import React from "react"; import useCounterTimerStore from "./useCounterTimerStore"; const Example_2 = () => { const { counter, user_name, dispatch } = useCounterTimerStore((state) => ({ counter: state.counter, user_name: state.user.name })); // using selector return ( <div> <h4>Example_2</h4> <h2>User Name : {user_name}</h2> <h2>Counter Value : {counter}</h2> <div> <button onClick={dispatch.incrementCounter}>Increment Counter</button> <button style={{ marginLeft: 10 }} onClick={dispatch.decrementTimer}> Decrement Timer </button> </div> </div> ); }; export default Example_2; ``` ### Example 3: Sharing State Between Components Multiple components can share the same store and stay in sync with state updates. ```tsx import { create, store } from "zippy-store"; const useAuthStore = create("authStore", (set, get) => ({ isAuthenticated: false, user: null, login: (user) => set({ isAuthenticated: true, user }), logout: () => set({ isAuthenticated: false, user: null }), })); import React from "react"; import useAuthStore from "./authStore"; // Assuming the store is in authStore.ts const Header = () => { const { isAuthenticated, user, dispatch } = useAuthStore(); return ( <header> {isAuthenticated ? ( <div> Welcome, {user?.name}! <button onClick={dispatch.logout}>Logout</button> </div> ) : ( <button onClick={() => dispatch.login({ name: "Test User", email: "test@example.com" })}>Login</button> )} </header> ); }; const Profile = () => { const { isAuthenticated, user } = useAuthStore(); return ( <div> <h2>Profile</h2> {isAuthenticated ? ( <p>Email: {user?.email}</p> ) : ( <p>Please login to view your profile.</p> )} </div> ); }; ``` ### Example 4: Async Support zippy-store supports asynchronous state updates in actions. ```tsx import { create } from "zippy-store"; const useMoviesStore = create((set) => ({ data: {}, fetch: async () => { const response = await someApiCall() set({ data: respoonse.data }) }, })) // or const useMoviesStore = create((set) => ({ data: {}, fetch: () => { set(async () => { const response = await someApiCall() return { data: respoonse.data } }) }, })) ``` ### Example 4: Persistence Support zippy-store supports persistence for React and JavaScript apps (React Native is not supported yet). ```ts import { create } from "zippy-store"; const usePersistentStore = create("persistentStore", (set, get) => ({ theme: "light", setTheme: (theme: string) => set(() => ({ theme })), }), true); // Enable persistence with true as the third parameter ``` ### Creating a Store and using it directly in JavaScript, React and React Native apps You can access the underlying store object for more advanced use cases and in non-React JavaScript environments(non React Components). ```ts import { store } from 'zippy-store'; const { dispatch } = store.createStore('counterTimerStore', (set, get) => ({ counter: 0, timer: 60, user: { name: "John Doe", age: 30 }, incrementCounter: () => set((state) => ({ counter: state.counter + 1 })), decrementTimer: () => set((state) => ({ timer: state.timer - 1 })), })); // Get the current state const counterTimerState = store.getState('counterTimerStore'); // Subscribe to changes const unsubscribe = store.subscribe('counterTimerStore', (newState) => { console.log('Store updated:', newState); }); // Update the state directly dispatch.incrementCounter(); // or const actions = store.getActions('counterTimerStore'); actions.incrementCounter(); // or store.setState('counterTimerStore', (state) => ({ counter: state.counter + 1 })); // Unsubscribe when done unsubscribe(); ``` ## API ### `create(storeKey: string, stateAndActionsFn: (set, get) => State & Partial<Actions>, persist?: boolean): Hook` Creates a new store for the given `storeKey`. #### Arguments: - `storeKey`: Unique identifier for the store. - `stateAndActionsFn`: A function with the initial state and actions. `set` allows updating the state. `get` allows accessing the state. - `persist`: Boolean flag to enable persistence (default: `false`). ##### Returns: - A hook that can be used in React components to access the state and actions. ### `store` The global store object with the following methods: - `store.createStore(key: string, stateAndActionsFn: (setState) => State & Actions, persist?: boolean): State`. Initializes the store with the given `key` and `stateAndActionsFn` and returns the dispatch object with actions. - `store.getActions(key: string): Actions` Returns the current actions of a given `storeKey`. - `store.getState(key: string): State` Returns the current state of a given `storeKey`. - `store.setState(key: string, newStateCb: (state) => Partial<State>)` Updates the state for a given `storeKey`. - `store.subscribe(key: string, callback: (newState) => void): UnsubscribeFn` Subscribes to state changes of a given `storeKey` and returns an unsubscribe function. ## License MIT ***Powered by Harish Ponna @2025***