
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
react-rooks
Advanced tools
React Rooks is a lightweight state management library for React that brings the simplicity of
useStateto global and contextual state. Just like a chess rook moves in straight lines, your state updates are direct, predictable, and powerful.
🎮 Try the Interactive Demo → | 📖 Documentation | 🚀 Quick Start
If you love useState but need global state, React Rooks is for you. It's designed to feel exactly like React's built-in hooks while providing powerful state management capabilities.
💡 New to React Rooks? Check out our interactive demo to see all features in action with real-time state inspection and code tooltips!
useState but for global state| Feature | React Rooks | Redux Toolkit | Zustand | Jotai | Valtio |
|---|---|---|---|---|---|
| Bundle Size | ~2KB | ~47KB | ~8KB | ~13KB | ~14KB |
| useState-like API | ✅ Perfect | ❌ Complex | ✅ Good | ✅ Good | ⚠️ Different |
| TypeScript Support | ✅ Excellent | ✅ Good | ✅ Good | ✅ Excellent | ✅ Good |
| Zero Boilerplate | ✅ | ❌ | ✅ | ✅ | ✅ |
| Multiple Stores | ✅ | ✅ | ✅ | ✅ | ✅ |
| Scoped Providers | ✅ | ❌ | ⚠️ Manual | ✅ | ⚠️ Manual |
| Schema Validation | 🔄 Coming | ❌ | ❌ | ❌ | ❌ |
| Reducers | ✅ Optional | ✅ Required | ✅ Optional | ✅ | ❌ |
| DevTools | ❌ | ✅ | ✅ | ✅ | ✅ |
# Using bun (recommended)
bun add react-rooks
# Using npm
npm install react-rooks
# Using yarn
yarn add react-rooks
Experience React Rooks in action with our interactive demo:
# Clone and run the demo locally
git clone https://github.com/your-username/react-rooks.git
cd react-rooks/demo
bun install
bun dev
Demo Features:
useRook and reducersimport { createRook } from "react-rooks";
// 1. Create your store (like useState but global)
export const [UserStore, useUser] = createRook({
name: "John Doe",
email: "john@example.com",
theme: "light" as "light" | "dark",
});
// 2. Use anywhere in your app
function UserProfile() {
const [name, setName] = useUser("name");
const [email, setEmail] = useUser("email");
return (
<div>
<input value={name} onChange={(e) => setName(e.target.value)} />
<input value={email} onChange={(e) => setEmail(e.target.value)} />
</div>
);
}
// 3. Wrap your app
function App() {
return (
<UserStore>
<UserProfile />
</UserStore>
);
}
React Rooks is designed to feel exactly like useState:
| useState (React) | useRook (React Rooks) |
|---|---|
const [count, setCount] = useState(0) | const [count, setCount] = useRook("count") |
| Component-scoped | Global/contextual scope |
| Direct updates | Direct updates |
| Type-safe | Type-safe |
| Simple API | Simple API |
// Before: Component state
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount((c) => c + 1)}>{count}</button>;
}
// After: Global state (same API!)
const [CounterStore, useCounter] = createRook({ count: 0 });
function Counter() {
const [count, setCount] = useCounter("count");
return <button onClick={() => setCount((c) => c + 1)}>{count}</button>;
}
React Rooks is actively developed with exciting features coming soon:
Experience the full power of React Rooks with our comprehensive demo application that showcases all features in an interactive environment.
git clone https://github.com/your-username/react-rooks.git
cd react-rooks/demo
bun install && bun dev
The demo includes 5 comprehensive examples that demonstrate:
useRook and reducer patterns💡 Perfect for Learning: Each example includes detailed explanations and shows best practices for different use cases.
useRook when the accessed key hasn't changed
// Only re-render when 'name' changes, not when another key changes
const [name] = useUser("name");
✅ Initialization Callbacks: Execute callbacks when store initialization is complete
const [UserStore] = createRook(
{ user: null },
{
onInitComplete: (store) => {
console.log("Store initialized:", store);
// Perfect for analytics, logging, or side effects
},
}
);
🏗️ Lazy Mounting: Allow components to render even before store initialization
Currently, Rook providers don't render their children until the store is fully initialized. This feature will allow components to mount immediately with loading states.
// Current behavior: Children don't render until store is ready
function App() {
return (
<UserStore>
{/* Children wait for store initialization */}
<UserProfile />
</UserStore>
);
}
// Future: Components can render with loading states before store is ready
function UserProfile() {
const { inited } = useRookState(UserStore);
const [user] = useUserRook("user");
if (!inited) return <Spinner />; // Shows immediately
return <div>{user.name}</div>;
}
import { createZodRook } from "react-rooks/zod";
import { z } from "zod";
const UserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.number().min(0).max(120),
});
const [UserStore, useUser] = createZodRook(UserSchema, {
validateOnUpdate: true,
onValidationError: (error) => {
// Handle validation errors gracefully
toast.error(`Invalid data: ${error.message}`);
},
});
// Advanced schema with conditional validation
const UserSchema = z
.object({
type: z.enum(["admin", "user"]),
permissions: z.array(z.string()).optional(),
})
.refine(
(data) => {
// Conditional validation: admins must have permissions
if (data.type === "admin") {
return data.permissions && data.permissions.length > 0;
}
return true;
},
{
message: "Admin users must have at least one permission",
}
);
createRook(initialStore, reducers?)Creates a global store with optional reducers.
import { createRook } from "react-rooks";
// Basic store
const [Store, useStore] = createRook({
count: 0,
user: { name: "", email: "" },
});
// With reducers
const [Store, useStore] = createRook(
{ count: 0 },
{
count: (state, action) => {
switch (action.type) {
case "increment":
return state + 1;
case "decrement":
return state - 1;
default:
return state;
}
},
}
);
useRook(key?)Hook to access store values.
// Access specific key
const [count, setCount] = useRook("count");
// Access entire store
const [store, setStore] = useRook();
// Functional updates
setCount((prevCount) => prevCount + 1);
// Direct updates
setCount(42);
RookContainerCombine multiple stores.
import { RookContainer } from "react-rooks";
const [UserStore] = createRook({ name: "" });
const [ThemeStore] = createRook({ mode: "light" });
function App() {
return (
<RookContainer rooks={[UserStore, ThemeStore]}>
<MyApp />
</RookContainer>
);
}
⚠️ Order Matters: Stores are nested from top to bottom. Components lower in the tree can access stores from higher levels.
// ✅ Correct: CartStore can access UserStore and ThemeStore
<RookContainer rooks={[UserStore, ThemeStore, CartStore]}>
<App />
</RookContainer>
// ❌ Wrong: UserStore can't access CartStore or ThemeStore
<RookContainer rooks={[CartStore, ThemeStore, UserStore]}>
<App />
</RookContainer>
Let's see the same shopping cart feature implemented across different state management solutions. Same functionality, different complexity.
import { createRook } from "react-rooks";
// 1. Create store (2 lines)
const [CartStore, useCart] = createRook({
items: [] as Array<{
id: number;
name: string;
price: number;
quantity: number;
}>,
total: 0,
});
// 2. Hook for actions (6 lines)
function useCartActions() {
const [items, setItems] = useCart("items");
const [, setTotal] = useCart("total");
const addItem = (item: (typeof items)[0]) => {
const newItems = [...items, item];
setItems(newItems);
setTotal(newItems.reduce((sum, i) => sum + i.price * i.quantity, 0));
};
const removeItem = (id: number) => {
const newItems = items.filter((i) => i.id !== id);
setItems(newItems);
setTotal(newItems.reduce((sum, i) => sum + i.price * i.quantity, 0));
};
return { addItem, removeItem };
}
// 3. Component (12 lines)
function ShoppingCart() {
const [items] = useCart("items");
const [total] = useCart("total");
const { addItem, removeItem } = useCartActions();
return (
<div>
<h2>
Cart ({items.length} items) - ${total.toFixed(2)}
</h2>
{items.map((item) => (
<div key={item.id}>
{item.name} - ${item.price} x {item.quantity}
<button onClick={() => removeItem(item.id)}>Remove</button>
</div>
))}
<button
onClick={() =>
addItem({ id: Date.now(), name: "New Item", price: 10, quantity: 1 })
}
>
Add Item
</button>
</div>
);
}
// 4. App wrapper (2 lines)
function App() {
return (
<CartStore>
<ShoppingCart />
</CartStore>
);
}
import { configureStore, createSlice, PayloadAction } from "@reduxjs/toolkit";
import { Provider, useSelector, useDispatch } from "react-redux";
// 1. Types (4 lines)
interface CartItem {
id: number;
name: string;
price: number;
quantity: number;
}
interface CartState {
items: CartItem[];
total: number;
}
// 2. Slice (22 lines)
const cartSlice = createSlice({
name: "cart",
initialState: {
items: [],
total: 0,
} as CartState,
reducers: {
addItem: (state, action: PayloadAction<CartItem>) => {
state.items.push(action.payload);
state.total = state.items.reduce(
(sum, item) => sum + item.price * item.quantity,
0
);
},
removeItem: (state, action: PayloadAction<number>) => {
state.items = state.items.filter((item) => item.id !== action.payload);
state.total = state.items.reduce(
(sum, item) => sum + item.price * item.quantity,
0
);
},
},
});
// 3. Store (3 lines)
const store = configureStore({
reducer: { cart: cartSlice.reducer },
});
type RootState = ReturnType<typeof store.getState>;
// 4. Actions (2 lines)
const { addItem, removeItem } = cartSlice.actions;
// 5. Component (20 lines)
function ShoppingCart() {
const { items, total } = useSelector((state: RootState) => state.cart);
const dispatch = useDispatch();
const handleAddItem = () => {
dispatch(
addItem({ id: Date.now(), name: "New Item", price: 10, quantity: 1 })
);
};
const handleRemoveItem = (id: number) => {
dispatch(removeItem(id));
};
return (
<div>
<h2>
Cart ({items.length} items) - ${total.toFixed(2)}
</h2>
{items.map((item) => (
<div key={item.id}>
{item.name} - ${item.price} x {item.quantity}
<button onClick={() => handleRemoveItem(item.id)}>Remove</button>
</div>
))}
<button onClick={handleAddItem}>Add Item</button>
</div>
);
}
// 6. App wrapper (6 lines)
function App() {
return (
<Provider store={store}>
<ShoppingCart />
</Provider>
);
}
import { create } from "zustand";
// 1. Types (4 lines)
interface CartItem {
id: number;
name: string;
price: number;
quantity: number;
}
interface CartStore {
items: CartItem[];
total: number;
addItem: (item: CartItem) => void;
removeItem: (id: number) => void;
}
// 2. Store (18 lines)
const useCartStore = create<CartStore>((set, get) => ({
items: [],
total: 0,
addItem: (item) =>
set((state) => {
const newItems = [...state.items, item];
return {
items: newItems,
total: newItems.reduce((sum, i) => sum + i.price * i.quantity, 0),
};
}),
removeItem: (id) =>
set((state) => {
const newItems = state.items.filter((i) => i.id !== id);
return {
items: newItems,
total: newItems.reduce((sum, i) => sum + i.price * i.quantity, 0),
};
}),
}));
// 3. Component (12 lines)
function ShoppingCart() {
const { items, total, addItem, removeItem } = useCartStore();
return (
<div>
<h2>
Cart ({items.length} items) - ${total.toFixed(2)}
</h2>
{items.map((item) => (
<div key={item.id}>
{item.name} - ${item.price} x {item.quantity}
<button onClick={() => removeItem(item.id)}>Remove</button>
</div>
))}
<button
onClick={() =>
addItem({ id: Date.now(), name: "New Item", price: 10, quantity: 1 })
}
>
Add Item
</button>
</div>
);
}
// 4. App (1 line)
function App() {
return <ShoppingCart />;
}
import { createContext, useContext, useState, ReactNode } from "react";
// 1. Types (4 lines)
interface CartItem {
id: number;
name: string;
price: number;
quantity: number;
}
interface CartContextType {
items: CartItem[];
total: number;
addItem: (item: CartItem) => void;
removeItem: (id: number) => void;
}
// 2. Context (2 lines)
const CartContext = createContext<CartContextType | undefined>(undefined);
// 3. Provider (23 lines)
function CartProvider({ children }: { children: ReactNode }) {
const [items, setItems] = useState<CartItem[]>([]);
const [total, setTotal] = useState(0);
const addItem = (item: CartItem) => {
const newItems = [...items, item];
setItems(newItems);
setTotal(newItems.reduce((sum, i) => sum + i.price * i.quantity, 0));
};
const removeItem = (id: number) => {
const newItems = items.filter((i) => i.id !== id);
setItems(newItems);
setTotal(newItems.reduce((sum, i) => sum + i.price * i.quantity, 0));
};
return (
<CartContext.Provider value={{ items, total, addItem, removeItem }}>
{children}
</CartContext.Provider>
);
}
// 4. Hook (5 lines)
function useCart() {
const context = useContext(CartContext);
if (!context) {
throw new Error("useCart must be used within CartProvider");
}
return context;
}
// 5. Component (12 lines)
function ShoppingCart() {
const { items, total, addItem, removeItem } = useCart();
return (
<div>
<h2>
Cart ({items.length} items) - ${total.toFixed(2)}
</h2>
{items.map((item) => (
<div key={item.id}>
{item.name} - ${item.price} x {item.quantity}
<button onClick={() => removeItem(item.id)}>Remove</button>
</div>
))}
<button
onClick={() =>
addItem({ id: Date.now(), name: "New Item", price: 10, quantity: 1 })
}
>
Add Item
</button>
</div>
);
}
// 6. App wrapper (3 lines)
function App() {
return (
<CartProvider>
<ShoppingCart />
</CartProvider>
);
}
| Metric | React Rooks | Redux Toolkit | Zustand | Context + useState |
|---|---|---|---|---|
| Total Lines of Code | 22 ⭐ | 65 | 35 | 45 |
| Concepts to Learn | 1 ⭐ | 5 | 2 | 3 |
| Boilerplate Required | Minimal ⭐ | Heavy | Medium | Medium |
| TypeScript Inference | Auto ⭐ | Manual | Manual | Manual |
| useState-like API | ✅ ⭐ | ❌ | ⚠️ | ✅ |
| Performance | Optimal ⭐ | Good | Good | Manual Optimization |
useState syntax you already knowuseStateSame functionality, 66% less code, 80% fewer concepts to learn. 🏆
// Create separate stores for different domains
const [UserStore, useUser] = createRook({
defaultStore: {
profile: { name: "", email: "" },
preferences: { theme: "light", notifications: true },
},
});
const [CartStore, useCart] = createRook({
defaultStore: {
items: [],
total: 0,
},
});
// Use them together
function App() {
return (
<RookContainer rooks={[UserStore, CartStore]}>
<Header />
<MainContent />
<Footer />
</RookContainer>
);
}
// Or scope them to specific parts of your app
function UserSection() {
return (
<UserStore>
<UserProfile />
<UserSettings />
</UserStore>
);
}
The order of stores in RookContainer is crucial! Stores are nested from top to bottom, so components can only access stores that are positioned above them in the array.
// 🏪 Three stores with different responsibilities
const [UserStore, useUser] = createRook({
defaultStore: {
user: { id: 1, name: "Alice", role: "admin" },
isLoggedIn: true,
},
});
const [ThemeStore, useTheme] = createRook({
defaultStore: {
mode: "light" as "light" | "dark",
primaryColor: "#3b82f6",
},
});
const [CartStore, useCart] = createRook({
defaultStore: {
items: [] as CartItem[],
total: 0,
},
});
// Component that consumes from multiple stores
function SmartCartManager() {
// ✅ Can access UserStore (positioned above)
const [user] = useUser("user");
const [isLoggedIn] = useUser("isLoggedIn");
// ✅ Can access ThemeStore (positioned above)
const [mode] = useTheme("mode");
// ✅ Can access CartStore (same level)
const [items, setItems] = useCart("items");
const addItem = () => {
if (!isLoggedIn) {
alert(`${user.name}, please log in first!`);
return;
}
const newItem = {
id: Date.now(),
name: `Item ${items.length + 1}`,
price: 29.99,
quantity: 1,
};
setItems([...items, newItem]);
};
return (
<div
style={{
backgroundColor: mode === "dark" ? "#1f2937" : "#f9fafb",
padding: "20px",
borderRadius: "8px",
}}
>
<h3>🛒 Cart for {user.name}</h3>
<p>Theme: {mode} mode</p>
<button onClick={addItem} disabled={!isLoggedIn}>
Add Item to Cart
</button>
<p>Items in cart: {items.length}</p>
</div>
);
}
// ✅ CORRECT: Proper order allows SmartCartManager to access all stores
function CorrectApp() {
return (
<RookContainer rooks={[UserStore, ThemeStore, CartStore]}>
<SmartCartManager />
</RookContainer>
);
}
// ❌ WRONG: CartStore is first, so SmartCartManager can't access UserStore/ThemeStore
function WrongApp() {
return (
<RookContainer rooks={[CartStore, UserStore, ThemeStore]}>
<SmartCartManager /> {/* This will throw errors! */}
</RookContainer>
);
}
// 📊 Recommended order patterns:
// For E-commerce app:
<RookContainer rooks={[
AuthStore, // 1. Authentication (most fundamental)
ThemeStore, // 2. UI preferences
UserStore, // 3. User data
CartStore, // 4. Shopping functionality
CheckoutStore // 5. Specific features
]}>
// For Admin dashboard:
<RookContainer rooks={[
AuthStore, // 1. Who is logged in?
PermissionStore,// 2. What can they do?
ThemeStore, // 3. How does it look?
DataStore // 4. Application data
]}>
// For Blog:
<RookContainer rooks={[
UserStore, // 1. Reader preferences
ThemeStore, // 2. Display settings
PostStore, // 3. Content data
CommentStore // 4. Interactive features
]}>
const [TodoStore, useTodos] = createRook(
{
todos: [],
filter: "all",
},
{
todos: (state, action) => {
switch (action.type) {
case "ADD_TODO":
return [...state, { id: Date.now(), text: action.text, done: false }];
case "TOGGLE_TODO":
return state.map((todo) =>
todo.id === action.id ? { ...todo, done: !todo.done } : todo
);
case "DELETE_TODO":
return state.filter((todo) => todo.id !== action.id);
default:
return state;
}
},
}
);
function TodoList() {
const [todos, dispatch] = useTodos("todos");
const addTodo = (text: string) => {
dispatch({ type: "ADD_TODO", text });
};
const toggleTodo = (id: number) => {
dispatch({ type: "TOGGLE_TODO", id });
};
}
import { createRook } from "react-rooks";
// Initialize with server data
const [AppStore, useApp] = createRook({
user:
typeof window !== "undefined"
? JSON.parse(localStorage.getItem("user") || "null")
: null,
theme:
typeof window !== "undefined"
? localStorage.getItem("theme") || "light"
: "light",
});
// Hydrate on client
function App({ initialData }: { initialData?: any }) {
return (
<AppStore initialValue={initialData}>
<MyApp />
</AppStore>
);
}
____
| |
|____|
| |
|____|
| |
/|____|\
/_|____|_\
| |
|____|
/ \
/____\
[ DATA ]
Just like a rook in chess, React Rooks represents:
The rook doesn't move in complex patterns—it's straightforward, powerful, and reliable. That's exactly how your state management should be.
We welcome contributions! Please see our Contributing Guide for details.
git clone https://github.com/your-username/react-rooks.git
cd react-rooks
# Using bun (recommended)
bun install
bun run dev
# Using npm
npm install
npm run dev
# Using yarn
yarn install
yarn dev
MIT © Your Name
useState hookReady to move your state in straight lines? Start with React Rooks today! 🏰
FAQs
Store management for React and React Native with simple hooks !
We found that react-rooks demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.