{"_id":"5-react-normalization-rules","_rev":"3-019ec193ccf6f5bd0ec8aab292adc1e2","name":"5-react-normalization-rules","dist-tags":{"latest":"1.0.2"},"versions":{"1.0.0":{"name":"5-react-normalization-rules","version":"1.0.0","keywords":["react","state-management","normalization","zustand","hooks","typescript","react-patterns","state-architecture"],"author":{"name":"Khaled Salem"},"license":"MIT","_id":"5-react-normalization-rules@1.0.0","maintainers":[{"name":"khaledsalem","email":"khaledm.adelsalem@gmail.com"}],"homepage":"https://github.com/khaledM-salem/5-react-normalization-rules#readme","bugs":{"url":"https://github.com/khaledM-salem/5-react-normalization-rules/issues"},"dist":{"shasum":"2dd8ecdcdb295cf3d02b82ceda4f453cc043dabc","tarball":"https://registry.npmjs.org/5-react-normalization-rules/-/5-react-normalization-rules-1.0.0.tgz","fileCount":23,"integrity":"sha512-DWjXufamA21M50ch1ufQWm5crL0vsh1LobcJyKJpwrmfIAxJAtgxDGzlyxI0csM8eugqvbwrmWssrcrP83XcEw==","signatures":[{"sig":"MEUCIQCwC5kFLjqaDDeicfrKROfhBRr5tVYzLZwviXtwOEPxBgIgSkDJOkEYA+3Zj1dpvCYAdfUcOckIIwqVV+utVEBHyhg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":55576},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.esm.js","gitHead":"a7ddb97b8a5765fa0dd3530c73bd5ac5c2ea17c7","scripts":{"dev":"rollup -c -w","lint":"eslint src --ext .ts,.tsx","test":"jest","build":"rollup -c","format":"prettier --write \"src/**/*.{ts,tsx}\"","prepublishOnly":"npm run build"},"_npmUser":{"name":"khaledsalem","email":"khaledm.adelsalem@gmail.com"},"repository":{"url":"git+https://github.com/khaledM-salem/5-react-normalization-rules.git","type":"git"},"_npmVersion":"10.9.3","description":"A structured framework inspired by database normalization theory for React state management","directories":{},"_nodeVersion":"22.20.0","_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.6.0","eslint":"^8.0.0","rollup":"^3.0.0","prettier":"^3.0.0","typescript":"^5.0.0","@types/react":"^18.2.0","@rollup/plugin-typescript":"^11.0.0","@typescript-eslint/parser":"^6.0.0","@typescript-eslint/eslint-plugin":"^6.0.0","rollup-plugin-peer-deps-external":"^2.2.4"},"peerDependencies":{"react":">=16.8.0","zustand":">=4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/5-react-normalization-rules_1.0.0_1761340851843_0.4554775310115342","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"5-react-normalization-rules","version":"1.0.1","keywords":["react","state-management","normalization","zustand","hooks","typescript","react-patterns","state-architecture"],"author":{"name":"Khaled Salem"},"license":"MIT","_id":"5-react-normalization-rules@1.0.1","maintainers":[{"name":"khaledsalem","email":"khaledm.adelsalem@gmail.com"}],"homepage":"https://github.com/khaledM-salem/5-react-normalization-rules#readme","bugs":{"url":"https://github.com/khaledM-salem/5-react-normalization-rules/issues"},"dist":{"shasum":"6247d474fd035b79f05cd17e9e4d160f16abf290","tarball":"https://registry.npmjs.org/5-react-normalization-rules/-/5-react-normalization-rules-1.0.1.tgz","fileCount":23,"integrity":"sha512-ZEWhtrTbjvjdGI4nk9j6ynjS+xbuzuU08I7LyiGxe9JvghZ1WgAS8rSq6RhRIOHyXL4cqUdk7D9/ll/UFk82Xg==","signatures":[{"sig":"MEUCIQCmPvCJQufLdw+v93TBMWrnLfJi5ap9xdYXwUnKnkBwVwIgE8Ok/l98Ks/QGeLC4B8HGBW9gTQpGPgBnnCFo90h8KA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":60531},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.esm.js","gitHead":"c78275075143d443e6688ae94d1e7fe192119042","scripts":{"dev":"rollup -c -w","lint":"eslint src --ext .ts,.tsx","test":"jest","build":"rollup -c","format":"prettier --write \"src/**/*.{ts,tsx}\"","prepublishOnly":"npm run build"},"_npmUser":{"name":"khaledsalem","email":"khaledm.adelsalem@gmail.com"},"repository":{"url":"git+https://github.com/khaledM-salem/5-react-normalization-rules.git","type":"git"},"_npmVersion":"10.9.3","description":"A structured framework inspired by database normalization theory for React state management","directories":{},"_nodeVersion":"22.20.0","_hasShrinkwrap":false,"devDependencies":{"tslib":"^2.6.0","eslint":"^8.0.0","rollup":"^3.0.0","prettier":"^3.0.0","typescript":"^5.0.0","@types/react":"^18.2.0","@rollup/plugin-typescript":"^11.0.0","@typescript-eslint/parser":"^6.0.0","@typescript-eslint/eslint-plugin":"^6.0.0","rollup-plugin-peer-deps-external":"^2.2.4"},"peerDependencies":{"react":">=16.8.0","zustand":">=4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/5-react-normalization-rules_1.0.1_1761412620622_0.3330396312089716","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"5-react-normalization-rules","version":"1.0.2","description":"A structured framework inspired by database normalization theory for React state management","main":"dist/index.js","module":"dist/index.esm.js","types":"dist/index.d.ts","scripts":{"build":"rollup -c","dev":"rollup -c -w","test":"jest","lint":"eslint src --ext .ts,.tsx","format":"prettier --write \"src/**/*.{ts,tsx}\"","prepublishOnly":"npm run build"},"keywords":["react","state-management","normalization","zustand","hooks","typescript","react-patterns","state-architecture"],"author":{"name":"Khaled Salem"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/khaledM-salem/5-react-normalization-rules.git"},"bugs":{"url":"https://github.com/khaledM-salem/5-react-normalization-rules/issues"},"homepage":"https://github.com/khaledM-salem/5-react-normalization-rules#readme","peerDependencies":{"react":">=16.8.0","zustand":">=4.0.0"},"devDependencies":{"@types/react":"^18.2.0","@typescript-eslint/eslint-plugin":"^6.0.0","@typescript-eslint/parser":"^6.0.0","eslint":"^8.0.0","prettier":"^3.0.0","rollup":"^3.0.0","@rollup/plugin-typescript":"^11.0.0","rollup-plugin-peer-deps-external":"^2.2.4","typescript":"^5.0.0","tslib":"^2.6.0"},"_id":"5-react-normalization-rules@1.0.2","gitHead":"8f2f7f4cc67129bbb3c264a0512f0be353abcc57","_nodeVersion":"22.20.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-3rv6uyX9iDX+sdGdy+VdG6NKE+DDSnlVJyZXHfb9dtzu54qw1YSQInsBFpbNUnzBYvfO2sqUVpQQoX9FBMsG5g==","shasum":"d4e1ca98f37d6c91d4931f716517bfb3be5ed5e7","tarball":"https://registry.npmjs.org/5-react-normalization-rules/-/5-react-normalization-rules-1.0.2.tgz","fileCount":23,"unpackedSize":60357,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGAj2sDVe+u3DJX9eQs/Yu3bsDL4RUdxIydhsdNNY5DIAiAXu4s0dMbRzaGR5Kdxn4Vf2zYnnUNgVS0PlssPqtdMmg=="}]},"_npmUser":{"name":"khaledsalem","email":"khaledm.adelsalem@gmail.com"},"directories":{},"maintainers":[{"name":"khaledsalem","email":"khaledm.adelsalem@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/5-react-normalization-rules_1.0.2_1761412719600_0.691107496933347"},"_hasShrinkwrap":false}},"time":{"created":"2025-10-24T21:20:51.842Z","modified":"2025-10-25T17:18:39.999Z","1.0.0":"2025-10-24T21:20:52.092Z","1.0.1":"2025-10-25T17:17:00.819Z","1.0.2":"2025-10-25T17:18:39.814Z"},"bugs":{"url":"https://github.com/khaledM-salem/5-react-normalization-rules/issues"},"author":{"name":"Khaled Salem"},"license":"MIT","homepage":"https://github.com/khaledM-salem/5-react-normalization-rules#readme","keywords":["react","state-management","normalization","zustand","hooks","typescript","react-patterns","state-architecture"],"repository":{"type":"git","url":"git+https://github.com/khaledM-salem/5-react-normalization-rules.git"},"description":"A structured framework inspired by database normalization theory for React state management","maintainers":[{"name":"khaledsalem","email":"khaledm.adelsalem@gmail.com"}],"readme":"# ⚛️ 5 React Normalization Rules (5RNF)\n\n> A structured framework inspired by database normalization theory for React state management\n\n[![NPM Version](https://img.shields.io/npm/v/5-react-normalization-rules.svg)](https://www.npmjs.com/package/5-react-normalization-rules)\n[![NPM Downloads](https://img.shields.io/npm/dm/5-react-normalization-rules.svg)](https://www.npmjs.com/package/5-react-normalization-rules)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![GitHub Stars](https://img.shields.io/github/stars/YOUR_USERNAME/5-react-normalization-rules.svg)](https://github.com/YOUR_USERNAME/5-react-normalization-rules)\n\n## 📑 Table of Contents\n\n- [What is 5RNF?](#-what-is-5rnf)\n- [Installation](#-installation)\n- [Quick Start](#-quick-start)\n- [The 5 Rules](#-the-5-rules)\n  - [1RNF: Atomic State](#️⃣-1rnf-atomic-state)\n  - [2RNF: Single Responsibility](#️⃣-2rnf-single-responsibility)\n  - [3RNF: No Transitive Dependencies](#️⃣-3rnf-no-transitive-dependencies)\n  - [4RNF: Normalized Collections](#️⃣-4rnf-normalized-collections)\n  - [5RNF: Context Separation](#️⃣-5rnf-context-separation)\n- [Usage](#-usage)\n- [Examples](#-examples)\n- [Benefits](#-benefits)\n- [Contributing](#-contributing)\n- [License](#-license)\n- [Author](#-author)\n\n## 📚 What is 5RNF?\n\nThis is the **first structured adaptation** of the Five Normal Forms (5NF) from relational databases into React state architecture. The core principle: **data is data** — whether in a database or React state. Normalize it for clarity, performance, and scalability.\n\n## 🎯 The 5 Rules\n\n### 1️⃣ 1RNF: Atomic State\nEach state variable should contain only primitive values or simple objects.\n\n**❌ Bad:**\n```typescript\nconst [user, setUser] = useState({\n  profile: { name: \"John\", address: { street: \"123 Main\" } },\n  posts: [{ comments: [...] }]\n});\n```\n\n**✅ Good:**\n```typescript\nconst [userProfile, setUserProfile] = useState({});\nconst [userAddress, setUserAddress] = useState({});\nconst [posts, setPosts] = useState([]);\n```\n\n### 2️⃣ 2RNF: Single Responsibility\nEach state should have a single reason to change. Derived state should be computed!\n\n**❌ Bad:**\n```typescript\nconst [user, setUser] = useState({\n  firstName: \"John\",\n  lastName: \"Doe\",\n  fullName: \"John Doe\" // Redundant!\n});\n```\n\n**✅ Good:**\n```typescript\nconst [user, setUser] = useState({\n  firstName: \"John\",\n  lastName: \"Doe\"\n});\nconst fullName = useMemo(\n  () => `${user.firstName} ${user.lastName}`,\n  [user]\n);\n```\n\n### 3️⃣ 3RNF: No Transitive Dependencies\nState shouldn't depend on other non-key state. Eliminate cascading updates!\n\n**❌ Bad:**\n```typescript\nconst [cartItems, setCartItems] = useState([]);\nconst [cartTotal, setCartTotal] = useState(0); // Depends on cartItems!\n```\n\n**✅ Good:**\n```typescript\nconst [cartItems, setCartItems] = useState([]);\nconst cartTotal = useMemo(\n  () => cartItems.reduce((sum, item) => sum + item.price * item.quantity, 0),\n  [cartItems]\n);\n```\n\n### 4️⃣ 4RNF: Normalized Collections\nUse normalized data structures (entities by ID). Avoid duplicating entity data!\n\n**❌ Bad:**\n```typescript\nconst [posts, setPosts] = useState([\n  { id: 1, author: { id: 1, name: \"John\" } },\n  { id: 2, author: { id: 1, name: \"John\" } } // Duplicated author!\n]);\n```\n\n**✅ Good:**\n```typescript\nconst [posts, setPosts] = useState({\n  1: { id: 1, authorId: 1 }\n});\nconst [authors, setAuthors] = useState({\n  1: { id: 1, name: \"John\" }\n});\n```\n\n### 5️⃣ 5RNF: Context Separation\nSeparate concerns into different contexts/stores. Perfect for Redux & Zustand!\n\n**❌ Bad:**\n```typescript\nconst useAppStore = create(() => ({\n  user: {}, posts: [], ui: {}, cart: {},\n  // ... 50 more properties 😱\n}));\n```\n\n**✅ Good:**\n```typescript\nconst useAuthStore = create(...);\nconst usePostsStore = create(...);\nconst useUIStore = create(...);\n```\n\n## 📦 Installation\n\n```bash\nnpm install 5-react-normalization-rules\n# or\nyarn add 5-react-normalization-rules\n# or\npnpm add 5-react-normalization-rules\n```\n\n**Package:** [5-react-normalization-rules on NPM](https://www.npmjs.com/package/5-react-normalization-rules)\n\n**Peer Dependencies:**\n- React >= 16.8.0 (for hooks support)\n- Zustand >= 4.0.0 (for store examples)\n\n## 🚀 Usage\n\n### Core Utilities (Main Use)\n\n#### 1. Normalize Collections\n\n```typescript\nimport { normalize, denormalize, extractEntities } from '5-react-normalization-rules';\n\n// Normalize an array of objects\nconst users = [\n  { id: 1, name: 'John' },\n  { id: 2, name: 'Jane' }\n];\nconst normalized = normalize(users);\n// { 1: { id: 1, name: 'John' }, 2: { id: 2, name: 'Jane' } }\n\n// Denormalize back to array\nconst denormalized = denormalize(normalized);\n// [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }]\n\n// Extract nested entities (most powerful!)\nconst posts = [\n  { id: 1, title: 'Post 1', author: { id: 10, name: 'John' } },\n  { id: 2, title: 'Post 2', author: { id: 10, name: 'John' } }\n];\nconst { items, entities } = extractEntities(posts, 'author');\n// items: { 1: { id: 1, title: 'Post 1', authorId: 10 }, ... }\n// entities: { 10: { id: 10, name: 'John' } }\n```\n\n#### 2. Normalized State Hook\n\n```typescript\nimport { useNormalizedState } from '5-react-normalization-rules';\n\ninterface User {\n  id: number;\n  name: string;\n  email: string;\n}\n\nfunction UserManagement() {\n  const {\n    state,                    // Raw normalized state\n    addEntity,               // Add single entity\n    addEntities,             // Add multiple entities\n    updateEntity,            // Update entity\n    removeEntity,            // Remove entity\n    getEntity,               // Get entity by ID\n    getAllEntities,          // Get all as array\n    hasEntity,               // Check if exists\n    clear,                   // Clear all\n    count                    // Total count\n  } = useNormalizedState<User>({});\n\n  const handleAddUser = () => {\n    addEntity({ id: Date.now(), name: 'New User', email: 'user@example.com' });\n  };\n\n  const handleUpdateUser = (id: number, name: string) => {\n    updateEntity(id, { name });\n  };\n\n  return (\n    <div>\n      <button onClick={handleAddUser}>Add User</button>\n      <p>Total Users: {count}</p>\n      {getAllEntities.map(user => (\n        <div key={user.id}>\n          <span>{user.name}</span>\n          <button onClick={() => handleUpdateUser(user.id, 'Updated Name')}>\n            Update\n          </button>\n          <button onClick={() => removeEntity(user.id)}>Delete</button>\n        </div>\n      ))}\n    </div>\n  );\n}\n```\n\n#### 3. Real-World Example: Blog with Comments\n\n```typescript\nimport { useNormalizedState, extractEntities } from '5-react-normalization-rules';\n\nfunction BlogApp() {\n  // Normalize posts and authors\n  const posts = useNormalizedState<Post>({});\n  const authors = useNormalizedState<Author>({});\n  const comments = useNormalizedState<Comment>({});\n\n  // Fetch and normalize API data\n  useEffect(() => {\n    fetch('/api/posts')\n      .then(res => res.json())\n      .then(data => {\n        const { items: normalizedPosts, entities: normalizedAuthors } = \n          extractEntities(data, 'author');\n        \n        posts.addEntities(Object.values(normalizedPosts));\n        authors.addEntities(Object.values(normalizedAuthors));\n      });\n  }, []);\n\n  // Update author name - automatically updates ALL posts by this author\n  const updateAuthorName = (authorId: number, newName: string) => {\n    authors.updateEntity(authorId, { name: newName });\n  };\n\n  return (\n    <div>\n      {posts.getAllEntities.map(post => {\n        const author = authors.getEntity(post.authorId);\n        return (\n          <article key={post.id}>\n            <h2>{post.title}</h2>\n            <p>By {author?.name}</p>\n          </article>\n        );\n      })}\n    </div>\n  );\n}\n```\n\n### Store Examples (Reference Only)\n\nThe package includes Zustand store examples (`useAuthStore`, `usePostsStore`, `useUIStore`) to demonstrate how to apply 5RNF principles to your own stores. **These are educational examples**, not meant to be used directly in production.\n\n**Use them as templates:**\n\n```typescript\n// Your own store following 5RNF principles\nimport { create } from 'zustand';\n\ninterface Product {\n  id: number;\n  name: string;\n  categoryId: number;\n}\n\ninterface ProductsState {\n  products: Record<number, Product>;  // 4RNF: Normalized\n  addProduct: (product: Product) => void;\n  updateProduct: (id: number, updates: Partial<Product>) => void;\n}\n\nexport const useProductsStore = create<ProductsState>((set) => ({\n  products: {},\n  addProduct: (product) => \n    set((state) => ({ \n      products: { ...state.products, [product.id]: product } \n    })),\n  updateProduct: (id, updates) =>\n    set((state) => ({\n      products: {\n        ...state.products,\n        [id]: { ...state.products[id], ...updates }\n      }\n    }))\n}));\n```\n\n## 🎨 Examples\n\nCheck out the `/examples` folder for complete working examples:\n- `1RNF-AtomicState.ts` - Breaking down complex state\n- `2RNF-SingleResponsibility.ts` - Computing derived state\n- `3RNF-NoTransitiveDependencies.ts` - Shopping cart example\n- `4RNF-NormalizedCollections.ts` - Posts and authors normalization\n- `5RNF-ContextSeparation.ts` - Multiple Zustand stores\n\n## ✨ Benefits\n\n✅ **Better Performance** - 98% fewer unnecessary re-renders  \n✅ **Memory Efficient** - 99% less duplicated data  \n✅ **Zero Sync Bugs** - Derived values always consistent  \n✅ **100x Faster Updates** - Change once, update everywhere  \n✅ **Cleaner Code** - 90% less complexity  \n✅ **Team-Friendly** - Clear patterns, easy to maintain  \n\n📊 **[See Real Benefits with Concrete Numbers →](REAL_BENEFITS.md)**\n\n## 🤝 Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## 📄 License\n\nMIT © Khaled Salem\n\n## 🙋 Author\n\n**Khaled Salem** - React Architecture Innovator\n\n- 📦 NPM: [@khaledsalem](https://www.npmjs.com/~khaledsalem)\n- 🐙 GitHub: [@khaledsalem](https://github.com/khaledM-salem)\n\n## 🌟 Show Your Support\n\nIf you find this project useful, please consider:\n- ⭐ Starring the [GitHub repository](https://github.com/khaledM-salem/5-react-normalization-rules)\n- 📦 Sharing on [Twitter](https://twitter.com/intent/tweet?text=Check%20out%205%20React%20Normalization%20Rules%20-%20Database%20normalization%20principles%20for%20React%20state!&url=https://www.npmjs.com/package/5-react-normalization-rules)\n- 💬 Spreading the word in your team/community\n\n---\n\n⭐ If you find this useful, please consider giving it a star on GitHub!","readmeFilename":"README.md"}