# 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***

