{"id":26836608,"url":"https://github.com/martyroque/nucleux","last_synced_at":"2026-05-05T12:33:24.400Z","repository":{"id":285147369,"uuid":"956909986","full_name":"martyroque/nucleux","owner":"martyroque","description":"Simple atomic state management for React. No providers, no boilerplate.","archived":false,"fork":false,"pushed_at":"2025-07-19T17:42:32.000Z","size":907,"stargazers_count":20,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-24T14:53:06.531Z","etag":null,"topics":["atomic","atomic-state","hooks","javascript","open-source","pubsub","react","react-hooks","react-native","state","state-management","store","typescript","typescript-library","typescript-react"],"latest_commit_sha":null,"homepage":"https://nucleux.dev/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/martyroque.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-03-29T05:15:53.000Z","updated_at":"2025-07-29T03:32:43.000Z","dependencies_parsed_at":"2025-03-29T21:22:58.040Z","dependency_job_id":"7eb8b25f-d9df-452e-bdc8-4355db1bb207","html_url":"https://github.com/martyroque/nucleux","commit_stats":null,"previous_names":["martyroque/nucleux","martyroque/nucleus"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/martyroque/nucleux","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martyroque%2Fnucleux","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martyroque%2Fnucleux/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martyroque%2Fnucleux/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martyroque%2Fnucleux/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/martyroque","download_url":"https://codeload.github.com/martyroque/nucleux/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martyroque%2Fnucleux/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32649577,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-05T11:29:49.557Z","status":"ssl_error","status_checked_at":"2026-05-05T11:29:48.587Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["atomic","atomic-state","hooks","javascript","open-source","pubsub","react","react-hooks","react-native","state","state-management","store","typescript","typescript-library","typescript-react"],"created_at":"2025-03-30T16:20:26.722Z","updated_at":"2026-05-05T12:33:24.388Z","avatar_url":"https://github.com/martyroque.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/logo.svg\" width=\"128\" height=\"128\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ci\u003eSimple, atomic hub for all your React application's state management needs.\u003c/i\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.org/package/nucleux\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/nucleux?color=brightgreen\u0026label=npm%20package\" alt=\"Current npm package version.\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## Why Nucleux?\n\n- **Zero boilerplate** - Write less, do more\n- **No providers** - Use state anywhere without wrapping components\n- **Atomic updates** - Only subscribed components re-render\n- **Framework agnostic** - Works with or without React\n\n## Installation\n\n```bash\nnpm install nucleux\n```\n\n## Quick Start\n\nCreate a store with atomic state:\n\n```javascript\nimport { Store } from 'nucleux';\n\nclass CounterStore extends Store {\n  count = this.atom(0);\n\n  increment() {\n    this.count.value += 1;\n  }\n}\n```\n\nUse it in React components:\n\n```javascript\nimport { useStore, useValue } from 'nucleux';\n\nfunction Counter() {\n  const store = useStore(CounterStore);\n  const count = useValue(store.count);\n\n  return \u003cbutton onClick={store.increment}\u003eCount: {count}\u003c/button\u003e;\n}\n```\n\nThat's it! No providers, no reducers, no dispatch.\n\n## Core Concepts\n\n### Atoms\n\nAtoms are reactive pieces of state. When you change an atom's value, only components subscribed to that specific atom will re-render.\n\n```javascript\nclass TodoStore extends Store {\n  todos = this.atom([]);\n  filter = this.atom('all');\n\n  addTodo(text) {\n    this.todos.value = [\n      ...this.todos.value,\n      { id: Date.now(), text, done: false },\n    ];\n  }\n}\n```\n\n### Three Ways to Use State\n\n#### 1. `useStore` - Get store methods\n\n```javascript\nconst todoStore = useStore(TodoStore);\n// Access: todoStore.addTodo(), todoStore.toggleTodo(), etc.\n```\n\n#### 2. `useValue` - Subscribe to specific atoms\n\n```javascript\nconst todos = useValue(todoStore.todos);\n// Or directly: const todos = useValue(TodoStore, 'todos');\n```\n\n#### 3. `useNucleux` - Get everything at once\n\n```javascript\nconst todo = useNucleux(TodoStore);\n// Access: todo.todos, todo.filter, todo.addTodo(), etc.\n```\n\n## Advanced Features\n\n### Memoization\n\nFurther improve atom updates and component re-renders:\n\n```javascript\nclass AppStore extends Store {\n  // Shallow memoization (default) - compares by reference\n  count = this.atom(0);\n\n  // Deep memoization - compares object content\n  user = this.atom(\n    { name: 'John', age: 30 },\n    { memoization: { type: 'deep' } },\n  );\n\n  // Custom memoization - use your own comparison logic\n  product = this.atom(\n    { name: 'Laptop', price: 999.99, discount: 10 },\n    {\n      memoization: {\n        type: 'custom',\n        compare: (a, b) =\u003e a.name === b.name \u0026\u0026 a.price === b.price,\n      },\n    },\n  );\n}\n```\n\nWorks with derived atoms too:\n\n```javascript\nclass TodoStore extends Store {\n  todos = this.atom([]);\n  filter = this.atom('all');\n\n  // Further improve updates when filtered result content is the same\n  filteredTodos = this.deriveAtom(\n    [this.todos, this.filter],\n    (todos, filter) =\u003e todos.filter((t) =\u003e t.status === filter),\n    { type: 'deep' },\n  );\n}\n```\n\n### Persistence\n\nSave state automatically:\n\n```javascript\nclass UserStore extends Store {\n  // Simple persistence\n  theme = this.atom('dark', { persistence: { persistKey: 'theme' } });\n\n  // With custom storage\n  profile = this.atom(\n    { name: '', email: '' },\n    {\n      persistence: {\n        persistKey: 'profile',\n        storage: AsyncStorage,\n      },\n    },\n  );\n}\n```\n\n### Derived State\n\nCompute values from multiple atoms:\n\n```javascript\nclass TodoStore extends Store {\n  todos = this.atom([]);\n  filter = this.atom('all');\n\n  filteredTodos = this.deriveAtom(\n    [this.todos, this.filter],\n    (todos, filter) =\u003e {\n      if (filter === 'done') return todos.filter((t) =\u003e t.done);\n      if (filter === 'pending') return todos.filter((t) =\u003e !t.done);\n      return todos;\n    },\n  );\n}\n```\n\n### Store Dependencies\n\nInject other stores:\n\n```javascript\nclass NotificationStore extends Store {\n  userStore = this.inject(UserStore);\n  notifications = this.atom([]);\n\n  constructor() {\n    super();\n    this.watchAtom(this.userStore.currentUser, (user) =\u003e {\n      if (user) this.loadNotifications(user.id);\n    });\n  }\n}\n```\n\n### Custom Storage (React Native)\n\nSet storage for entire store:\n\n```javascript\nimport AsyncStorage from '@react-native-async-storage/async-storage';\n\nclass AppStore extends Store {\n  storage = AsyncStorage;\n\n  settings = this.atom(\n    { notifications: true },\n    { persistence: { persistKey: 'settings' } },\n  );\n}\n```\n\nOr per atom:\n\n```javascript\nclass AppStore extends Store {\n  settings = this.atom(\n    { notifications: true },\n    {\n      persistence: {\n        persistKey: 'settings',\n        storage: AsyncStorage,\n      },\n    },\n  );\n}\n```\n\n### Debugging\n\nTrack atom changes during development:\n\n```javascript\nclass TodoStore extends Store {\n  todos = this.atom([]);\n  filter = this.atom('all');\n\n  constructor() {\n    super();\n\n    // Enable debugging in development\n    if (process.env.NODE_ENV === 'development') {\n      this.enableDebug();\n    }\n  }\n\n  addTodo(text) {\n    this.todos.value = [...this.todos.value, { id: Date.now(), text }];\n  }\n}\n```\n\n### Reset Functionality\n\nReset atoms to their initial values and clear persisted data when needed.\n\n#### Individual Atom Reset\n\n```javascript\nclass UserStore extends Store {\n  theme = this.atom('light', { persistence: { persistKey: 'theme' } });\n  username = this.atom('guest');\n}\n\nconst userStore = useStore(UserStore);\n\n// Reset atom to initial value and clear storage\nawait userStore.theme.reset();\n\n// Reset value but keep persisted data\nawait userStore.theme.reset({ clearPersisted: false });\n\n// Clear persisted data but keep current value\nawait userStore.theme.reset({ resetValue: false });\n```\n\n#### Store-Level Reset\n\n```javascript\nclass AppStore extends Store {\n  theme = this.atom('light', { persistence: { persistKey: 'theme' } });\n  language = this.atom('en', { persistence: { persistKey: 'language' } });\n  isOnline = this.atom(true); // No persistence\n}\n\nconst appStore = useStore(AppStore);\n\n// Reset all atoms (values + persistence)\nawait appStore.reset();\n\n// Reset specific atoms only\nawait appStore.reset({ atomKeys: ['theme', 'language'] });\n\n// Convenience methods\nawait appStore.clearPersistedData(); // Clear persisted data only\nawait appStore.resetValues(); // Reset values only\n```\n\n#### Common Use Cases\n\n```javascript\n// User logout - clear sensitive data\nawait userStore.reset({\n  atomKeys: ['profile', 'preferences'],\n  resetValues: true,\n  clearPersisted: true,\n});\n\n// App settings reset\nawait settingsStore.reset();\n```\n\n## React Native Setup\n\nInstall the polyfill and import it before Nucleux:\n\n```bash\nnpm install react-native-get-random-values\n```\n\n```javascript\n// App.js - Import this first!\nimport 'react-native-get-random-values';\nimport { useStore, useValue } from 'nucleux';\n```\n\n## Complete Example\n\n```javascript\nimport React from 'react';\nimport { Store, useNucleux } from 'nucleux';\n\nclass TodoStore extends Store {\n  todos = this.atom([]);\n\n  addTodo(text) {\n    const newTodo = { id: Date.now(), text, done: false };\n    this.todos.value = [...this.todos.value, newTodo];\n  }\n\n  toggleTodo(id) {\n    this.todos.value = this.todos.value.map((todo) =\u003e\n      todo.id === id ? { ...todo, done: !todo.done } : todo,\n    );\n  }\n}\n\nfunction TodoApp() {\n  const { todos, addTodo, toggleTodo } = useNucleux(TodoStore);\n  const [input, setInput] = React.useState('');\n\n  const handleAdd = () =\u003e {\n    if (input.trim()) {\n      addTodo(input.trim());\n      setInput('');\n    }\n  };\n\n  return (\n    \u003cdiv\u003e\n      \u003cdiv\u003e\n        \u003cinput\n          value={input}\n          onChange={(e) =\u003e setInput(e.target.value)}\n          placeholder=\"Add todo...\"\n        /\u003e\n        \u003cbutton onClick={handleAdd}\u003eAdd\u003c/button\u003e\n      \u003c/div\u003e\n\n      \u003cul\u003e\n        {todos.map((todo) =\u003e (\n          \u003cli key={todo.id}\u003e\n            \u003clabel\u003e\n              \u003cinput\n                type=\"checkbox\"\n                checked={todo.done}\n                onChange={() =\u003e toggleTodo(todo.id)}\n              /\u003e\n              {todo.text}\n            \u003c/label\u003e\n          \u003c/li\u003e\n        ))}\n      \u003c/ul\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n## Try It Live\n\n[View on CodeSandbox](https://codesandbox.io/p/sandbox/nucleux-react-qw58s4)\n\n## API Reference\n\n### Store Methods\n\n#### `this.atom(initialValue, options?)`\n\nCreate reactive state.\n\n**Options:**\n\n- `persistence` - Auto-save to storage\n  - `persistKey: string` - Storage key\n  - `storage?: SupportedStorage` - Custom storage (defaults to localStorage)\n- `memoization` - Control when updates trigger\n  - `type: 'shallow' | 'deep' | 'custom'` - Comparison strategy\n  - `compare?: (a, b) =\u003e boolean` - Custom comparator (for `type: 'custom'`)\n\n```javascript\n// Simple atom\ncount = this.atom(0);\n\n// With persistence\ntheme = this.atom('dark', {\n  persistence: { persistKey: 'app-theme' },\n});\n\n// With memoization\nuser = this.atom(\n  { name: 'John' },\n  {\n    memoization: { type: 'deep' },\n  },\n);\n\n// Combined options\nprofile = this.atom(\n  { name: '', email: '' },\n  {\n    persistence: { persistKey: 'profile' },\n    memoization: { type: 'deep' },\n  },\n);\n```\n\n#### `this.deriveAtom(atoms[], computeFn, memoization?)`\n\nCreate computed state that updates when source atoms change.\n\n```javascript\nfilteredTodos = this.deriveAtom(\n  [this.todos, this.filter],\n  (todos, filter) =\u003e todos.filter((t) =\u003e t.status === filter),\n  { type: 'deep' }, // Optional memoization\n);\n```\n\n#### `this.inject(StoreClass)`\n\nInject another store as a dependency.\n\n```javascript\nuserStore = this.inject(UserStore);\n```\n\n#### `this.watchAtom(atom, callback, immediate?)`\n\nWatch atom changes within the store.\n\n```javascript\nconstructor() {\n  super();\n  this.watchAtom(this.user, (newUser, prevUser) =\u003e {\n    console.log('User changed:', newUser);\n  });\n}\n```\n\n#### `this.enableDebug()`\n\nEnable console logging for all atom changes in the store.\n\n```javascript\nconstructor() {\n  super();\n\n  // Enable debugging in development\n  if (process.env.NODE_ENV === 'development') {\n    this.enableDebug();\n  }\n}\n```\n\n#### `atom.reset(options?)`\n\nReset atom to initial value and/or clear persisted data.\n\n**Options:**\n\n- `resetValue?: boolean` - Reset value to initial (default: true)\n- `clearPersisted?: boolean` - Clear persisted data from storage (default: true)\n\n```javascript\n// Reset everything\nawait userAtom.reset();\n\n// Reset value only\nawait userAtom.reset({ clearPersisted: false });\n\n// Clear storage only\nawait userAtom.reset({ resetValue: false });\n```\n\n#### `this.reset(options?)`\n\nReset multiple atoms in the store.\n\n**Options:**\n\n- `resetValues?: boolean` - Reset values to initial (default: true)\n- `clearPersisted?: boolean` - Clear persisted data (default: true)\n- `atomKeys?: string[]` - Specific atoms to reset (default: all atoms)\n\n```javascript\n// Reset all atoms\nawait this.reset();\n\n// Reset specific atoms\nawait this.reset({ atomKeys: ['theme', 'language'] });\n\n// Custom combination\nawait this.reset({\n  resetValues: false,\n  clearPersisted: true,\n  atomKeys: ['cache'],\n});\n```\n\n#### `this.clearPersistedData()`\n\nClear all persisted data without affecting current values.\n\n```javascript\nawait this.clearPersistedData();\n```\n\n#### `this.resetValues()`\n\nReset all atom values without affecting persisted data.\n\n```javascript\nawait this.resetValues();\n```\n\n### React Hooks\n\n#### `useStore(StoreClass)`\n\nGet store instance with methods.\n\n```javascript\nconst todoStore = useStore(TodoStore);\ntodoStore.addTodo('New task');\n```\n\n#### `useValue(atom)` or `useValue(StoreClass, 'atomKey')`\n\nSubscribe to atom value.\n\n```javascript\n// Direct atom access\nconst todos = useValue(todoStore.todos);\n\n// Store + key access\nconst todos = useValue(TodoStore, 'todos');\n```\n\n#### `useNucleux(StoreClass)`\n\nGet all methods and atom values.\n\n```javascript\nconst { todos, addTodo, removeTodo } = useNucleux(TodoStore);\n```\n\n---\n\n**Requirements:** Node ≥14, React ≥16.9.0 (optional)\n\n## Author\n\n**Marty Roque**\n\n- GitHub: [@martyroque](https://github.com/martyroque)\n- X: [@lmproque](https://x.com/lmproque)\n- LinkedIn: [@lmproque](https://www.linkedin.com/in/lmproque/)\n\n## License\n\n[ISC License](LICENSE)\n\nCopyright © 2025 [Marty Roque](https://github.com/martyroque).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartyroque%2Fnucleux","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmartyroque%2Fnucleux","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartyroque%2Fnucleux/lists"}