https://github.com/developerrejaul/zustic
A fast, minimal state management solution for React ecosystems. Works seamlessly with React, Next.js, and React Native, offering predictable state updates with a tiny footprint.
https://github.com/developerrejaul/zustic
expo hook nextjs react reactnative redux state-management zustand
Last synced: 2 months ago
JSON representation
A fast, minimal state management solution for React ecosystems. Works seamlessly with React, Next.js, and React Native, offering predictable state updates with a tiny footprint.
- Host: GitHub
- URL: https://github.com/developerrejaul/zustic
- Owner: DeveloperRejaul
- Created: 2026-01-07T04:00:51.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-02-14T17:19:20.000Z (2 months ago)
- Last Synced: 2026-02-15T01:28:01.528Z (2 months ago)
- Topics: expo, hook, nextjs, react, reactnative, redux, state-management, zustand
- Language: TypeScript
- Homepage: https://zustic.github.io
- Size: 105 KB
- Stars: 8
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Zustic
### Lightweight State Management for Modern React Applications
[](https://npm.im/zustic)
[](https://npm.im/zustic)
[](https://bundlephobia.com/result?p=zustic)
[](LICENSE)
A **fast, minimal state management solution** for React ecosystems. Works seamlessly with React, Next.js, and React Native with predictable state updates and a tiny footprint.
[๐ Documentation](https://zustic.github.io/) ยท [๐ Report Bug](https://github.com/DeveloperRejaul/zustic/issues) ยท [๐ก Request Feature](https://github.com/DeveloperRejaul/zustic/issues)
---
## Key Features
### Core Features
- **Ultra-Lightweight** โ Only ~500B (gzipped) with zero dependencies
- **Simple API** โ One function (`create`) to manage all your state
- **React Hooks** โ Native React hooks integration with automatic subscriptions
- **Multi-Platform** โ React, React Native, Next.js, and modern frameworks
- **Reactive Updates** โ Automatic re-renders with optimized batching
- **TypeScript First** โ Full type safety with perfect type inference
- **Production Ready** โ Battle-tested in real applications
### Advanced Capabilities
- **Store Middleware System** โ Extend state management with logging, persistence, validation, and more
- **Query System** โ Built-in API data fetching with automatic caching, mutations, and plugins
- **Automatic Caching** โ Smart cache management with configurable timeout
- **Direct State Access** โ `get()` function for reading state outside components
- **Selective Subscriptions** โ Components only re-render when their data changes
- **Fully Extensible** โ Build custom middleware and plugins for any use case
- **Easy Testing** โ Simple to test stores and API queries with middleware and async operations
- **Plugin System** โ Global hooks for authentication, logging, error handling
- **Framework Agnostic** โ Create middleware and plugins once, use everywhere
---
## Installation
Choose your favorite package manager:
```bash
# npm
npm install zustic
# yarn
yarn add zustic
# pnpm
pnpm add zustic
```
---
## Why Zustic?
### Size & Performance
| Metric | Zustic | Redux | Zustand | Context API |
|--------|--------|-------|---------|-------------|
| **Bundle Size** | ~500B | ~6KB | ~2KB | Built-in |
| **Performance** | Optimized | Good | Optimized | Re-renders |
| **Dependencies** | 0 | 0 | 0 | 0 |
### Developer Experience
- **Ultra-Simple API**: Master everything in 5 minutes
- **Zero Boilerplate**: No actions, reducers, or providers
- **TypeScript Native**: Perfect type inference out of the box
- **Great DX**: Intuitive `create()`, `set()`, `get()` functions
### Comparison with Other Libraries
| Feature | Zustic | Redux | Zustand | Context API |
|---------|--------|-------|---------|-------------|
| Bundle Size | ~500B | ~6KB | ~2KB | 0B |
| Learning Curve | โญ Easy | โญโญโญโญโญ Hard | โญโญ Easy | โญโญโญ Medium |
| Boilerplate | Minimal | Massive | Minimal | Some |
| TypeScript | Excellent | Good | Good | Good |
| Store Middleware | Built-in | Required | Optional | No |
| Query System | Built-in | Separate | Separate | No |
| Caching | Automatic | Optional | Optional | No |
| API Simplicity | Very Simple | Complex | Simple | Medium |
---
## Quick Start
### 1. Create Your Store
```typescript
import { create } from 'zustic';
type CounterStore = {
count: number;
inc: () => void;
dec: () => void;
reset: () => void;
};
export const useCounter = create((set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
dec: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}));
```
### 2. Use in Your Component
```typescript
import { useCounter } from './store';
function Counter() {
const { count, inc, dec, reset } = useCounter();
return (
Count: {count}
โ Increment
โ Decrement
Reset
);
}
export default Counter;
```
That's it! No providers, no boilerplate, just pure state management.
---
## Core Concepts
### Create a Store
The `create` function is the heart of Zustic:
```typescript
const useStore = create((set, get) => ({
// Your state and actions
}));
```
- **`set`**: Update state (supports partial updates and functions)
- **`get`**: Read current state (works outside components)
### Reading State in Components
```typescript
function Component() {
// Subscribe to entire store
const state = useStore();
// Or subscribe to specific properties (optimized)
const count = useStore((state) => state.count);
return
{count};
}
```
## Store Middleware System
Extend Zustic stores with powerful middleware for logging, persistence, validation, and more.
### Logger Middleware
```typescript
const logger = (): Middleware => (set, get) => (next) => async (partial) => {
console.log('Previous State:', get());
await next(partial);
console.log('New State:', get());
};
export const useStore = create(
(set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
}),
[logger()]
);
```
### Persistence Middleware
```typescript
const persist = (): Middleware => (set, get) => (next) => async (partial) => {
await next(partial);
localStorage.setItem('store', JSON.stringify(get()));
};
export const useStore = create(
(set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
}),
[persist()]
);
```
### Validation Middleware
```typescript
const validate = (): Middleware => (set, get) => (next) => async (partial) => {
// Validate before updating
if (typeof partial === 'object' && partial.count < 0) {
console.warn('Invalid state update');
return;
}
await next(partial);
};
export const useStore = create(
(set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
}),
[validate()]
);
```
### Multiple Middleware
```typescript
export const useStore = create(
(set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
}),
[logger(), persist(), validate()]
);
```
---
## Query System (API Data Fetching)
Zustic now includes a powerful query system for managing API requests with automatic caching, mutations, middleware, and plugins.
### Create an API
```typescript
import { createApi } from 'zustic/query';
type User = {
id: number;
name: string;
email: string;
};
const baseQuery = async (args: any) => {
try {
const response = await fetch(`https://api.example.com${args.url}`, {
method: args.method || 'GET',
headers: args.headers,
body: args.body ? JSON.stringify(args.body) : undefined,
});
const data = await response.json();
return { data };
} catch (error) {
return { error };
}
};
export const api = createApi({
baseQuery,
endpoints: (builder) => ({
getUsers: builder.query({
query: () => ({
url: '/users',
method: 'GET',
}),
transformResponse: (data) => data.map((u: User) => ({ ...u, name: u.name.toUpperCase() })),
}),
getUser: builder.query({
query: ({ id }) => ({
url: `/users/${id}`,
method: 'GET',
}),
}),
createUser: builder.mutation>({
query: (body) => ({
url: '/users',
method: 'POST',
body,
}),
onSuccess: (data) => console.log('User created:', data),
onError: (error) => console.error('Failed to create:', error),
}),
updateUser: builder.mutation>({
query: (body) => ({
url: `/users/${body.id}`,
method: 'PUT',
body,
}),
}),
}),
cacheTimeout: 5 * 60 * 1000, // 5 minutes
});
```
### Use Queries in Components
```typescript
import { api } from './api';
function UsersList() {
// Query hook automatically fetches on mount
const { data: users, isLoading, isError, error, reFetch } = api.useUsersQuery();
if (isLoading) return
Loading...;
if (isError) return Error: {error?.message};
return (
Users
reFetch()}>Refresh
{users?.map((user) => (
- {user.name}
))}
);
}
```
### Skip Queries (Conditional Fetching)
```typescript
function UserDetail({ userId }: { userId?: number }) {
// Only fetch when userId is provided
const { data: user, isLoading } = api.useGetUserQuery(
{ id: userId! },
{ skip: !userId }
);
if (!userId) return
Select a user;
if (isLoading) return Loading...;
return
{user?.name} ({user?.email});
}
```
### Use Mutations in Components
```typescript
function CreateUserForm() {
// Mutation hook returns [mutate, state]
const [createUser, { isLoading, isError, error, data, isSuccess }] = api.useCreateUserMutation();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
await createUser({
name: formData.get('name') as string,
email: formData.get('email') as string,
});
};
return (
{isLoading ? 'Creating...' : 'Create User'}
{isSuccess &&
}
{isError &&
Error: {error?.message}
}
);
}
```
### Query API Features
#### Transformations
```typescript
getUser: builder.query({
query: ({ id }) => ({
url: `/users/${id}`,
method: 'GET',
}),
// Transform the response data
transformResponse: (data) => ({
...data,
formattedDate: new Date(data.createdAt).toLocaleDateString(),
}),
// Transform errors
transformError: (error) => ({
message: error.message || 'Unknown error occurred',
code: error.code,
}),
// Transform request body
transformBody: (body) => ({
...body,
timestamp: Date.now(),
}),
// Transform request headers
transformHeader: (headers) => ({
...headers,
'Authorization': `Bearer ${getToken()}`,
}),
}),
```
#### Hooks and Callbacks
```typescript
createUser: builder.mutation({
query: (body) => ({
url: '/users',
method: 'POST',
body,
}),
onSuccess: async (data) => {
console.log( 'User created:', data)
},
onError: async (error) => {
console.error(' Failed:', error)
},
}),
```
#### Automatic Caching
```typescript
const api = createApi({
baseQuery,
endpoints: (builder) => ({
getUser: builder.query({
query: ({ id }) => ({
url: `/users/${id}`,
method: 'GET',
}),
}),
}),
cacheTimeout: 10 * 60 * 1000, // Cache for 10 minutes
});
// First call: fetches from API
const result1 = useGetUserQuery({ id: 1 });
// Second call (within cache timeout): uses cached data
const result2 = useGetUserQuery({ id: 1 });
// Force refetch
const result3 = await reFetch();
```
#### Custom Query Function
```typescript
getUserCustom: builder.query({
queryFnc: async (arg, baseQuery) => {
// Implement custom logic
const token = localStorage.getItem('token');
return baseQuery({
url: `/users/${arg.id}`,
method: 'GET',
headers: { Authorization: `Bearer ${token}` },
});
},
}),
```
---
## Query Middleware & Plugins
### Query-Level Middleware
```typescript
const requestLogger: ApiMiddleware = (ctx, next) => {
console.log('Request:', ctx.arg);
const result = await next();
console.log('Response:', result);
return result;
};
getUser: builder.query({
query: ({ id }) => ({
url: `/users/${id}`,
method: 'GET',
}),
middlewares: [requestLogger],
}),
```
### Global Plugins
```typescript
const authPlugin: ApiPlugin = {
name: 'auth-plugin',
beforeQuery: (ctx) => {
const token = localStorage.getItem('token');
if (!token) {
throw new Error('Not authenticated');
}
},
afterQuery: (result, ctx) => {
if (result.error?.status === 401) {
// Handle unauthorized
window.location.href = '/login';
}
},
onError: (error, ctx) => {
console.error('API Error:', error);
},
};
const api = createApi({
baseQuery,
endpoints: (builder) => ({
// endpoints...
}),
plugins: [authPlugin],
});
```
---
## Multi-Platform Examples
### React Web
```typescript
import { create } from 'zustic';
const useStore = create((set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
}));
export default function App() {
const { count, inc } = useStore();
return (
{count}
Increment
);
}
```
### React Native
```typescript
import { create } from 'zustic';
import { View, Text, Button } from 'react-native';
const useStore = create((set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
}));
export default function App() {
const { count, inc } = useStore();
return (
{count}
);
}
```
### Next.js
```typescript
'use client';
import { create } from 'zustic';
const useStore = create((set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
}));
export default function Page() {
const { count, inc } = useStore();
return (
{count}
Increment
);
}
```
---
## Testing
Zustic stores are easy to test:
```typescript
import { create } from 'zustic';
// Your store
const useStore = create((set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
reset: () => set({ count: 0 }),
}));
// Test it
describe('Counter Store', () => {
it('should increment count', () => {
useStore.set({ count: 0 });
useStore.get().inc();
expect(useStore.get().count).toBe(1);
});
it('should reset count', () => {
useStore.set({ count: 5 });
useStore.get().reset();
expect(useStore.get().count).toBe(0);
});
});
```
---
## Advanced Examples
### Async State
```typescript
const useUserStore = create((set, get) => ({
user: null,
loading: false,
error: null,
fetchUser: async (id: string) => {
set({ loading: true });
try {
const response = await fetch(`/api/users/${id}`);
const user = await response.json();
set({ user, loading: false, error: null });
} catch (error) {
set({ error: error.message, loading: false });
}
},
}));
```
### Computed State
```typescript
const useCartStore = create((set, get) => ({
items: [],
addItem: (item) => set((state) => ({
items: [...state.items, item],
})),
get total() {
return get().items.reduce((sum, item) => sum + item.price, 0);
},
}));
```
### Nested Stores
```typescript
const useAuthStore = create((set) => ({
user: null,
login: (user) => set({ user }),
logout: () => set({ user: null }),
}));
const useAppStore = create((set) => ({
auth: useAuthStore,
theme: 'light',
}));
```
---
## Resources
- ๐ **[Full Documentation](https://zustic.github.io/)** - Complete API reference and guides
- ๐ **[GitHub Issues](https://github.com/DeveloperRejaul/zustic/issues)** - Report bugs and request features
- ๐ฌ **[Discussions](https://github.com/DeveloperRejaul/zustic/discussions)** - Ask questions and share ideas
- ๐ฆ **[NPM Package](https://npm.im/zustic)** - Install and view package info
---
## API Reference
### `create(initializer, middlewares?)`
Creates a new store with state and actions.
**Parameters:**
- `initializer` - Function that receives `set` and `get`, returns initial state
- `middlewares` (optional) - Array of middleware functions
**Returns:**
- A hook function that provides access to store state and actions
**Example:**
```typescript
const useStore = create((set, get) => ({
value: 0,
increment: () => set((state) => ({ value: state.value + 1 })),
getValue: () => get().value,
}));
```
---
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request to the [GitHub repository](https://github.com/DeveloperRejaul/zustic).
---
## License
MIT License ยฉ 2024 [Rejaul Karim](https://github.com/DeveloperRejaul)
---
## Author
Created by **Rejaul Karim** - [GitHub](https://github.com/DeveloperRejaul)
---
### Made with โค๏ธ for the React community
โญ Star us on [GitHub](https://github.com/DeveloperRejaul/zustic) if you find this helpful!