{"id":17565107,"url":"https://github.com/gluecodes/storecle","last_synced_at":"2025-04-28T10:27:56.282Z","repository":{"id":41853286,"uuid":"385676291","full_name":"gluecodes/storecle","owner":"gluecodes","description":"A neat app state management and action orchestration for React and Solid.","archived":false,"fork":false,"pushed_at":"2022-04-26T10:19:59.000Z","size":641,"stargazers_count":27,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-18T15:16:19.764Z","etag":null,"topics":["react","reactjs","redux","solid","solidjs","state-management"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gluecodes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-07-13T16:58:01.000Z","updated_at":"2024-09-15T02:36:56.000Z","dependencies_parsed_at":"2022-08-11T19:31:00.635Z","dependency_job_id":null,"html_url":"https://github.com/gluecodes/storecle","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gluecodes%2Fstorecle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gluecodes%2Fstorecle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gluecodes%2Fstorecle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gluecodes%2Fstorecle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gluecodes","download_url":"https://codeload.github.com/gluecodes/storecle/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251294186,"owners_count":21566225,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["react","reactjs","redux","solid","solidjs","state-management"],"created_at":"2024-10-21T14:09:07.285Z","updated_at":"2025-04-28T10:27:56.252Z","avatar_url":"https://github.com/gluecodes.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Storecle\n\n**@gluecodes/storecle**\n\n[![NPM Version](https://img.shields.io/npm/v/@gluecodes/storecle-solid.svg?style=flat)](https://www.npmjs.com/package/@gluecodes/storecle-solid)\n\nA neat uni-directional app state management for [React](https://reactjs.org/) and [Solid](https://www.solidjs.com/) (:heart:).\n\n## Features\n\nStorecle uses a simple mental model which lets you access app-wide actions and their results by using Context API.\nIt consists of 4 main building blocks i.e. Store, User Actions (actions triggered by a user), Data Suppliers (actions executed prior to rendering) and Reload Types (action re-trigger groups).\nThe actions are just functions which are implicitly bound to the Store and write their results by returning/resolving.\nThen, their results are accessible by their own names.\n\nTo improve the code re-usability, Data Suppliers use a middleware pattern. They are executed in the order you specify and pass a snapshot of Store from one to another, letting you split the logic into small, specified functions.\n\n- It works with both [React](https://reactjs.org/) and [Solid](https://www.solidjs.com/) (it's framework agnostic to certain degree).\n- It uses Context API and `useEffect` / `createEffect` to provide action re-triggers based on specified Store changes.\n- It facilitates splitting the business logic into granual, re-usable functions by applying a middleware pattern.\n- It simplifies naming and reduces noise by letting you access action results by their own names.\n- It provides an elegant approach to actions feeding UI with incoming data (e.g. from Web Sockets).\n- It is made to work with your IDE's code auto-completion.\n\n## Motivation\n\nI :heart: Redux, but it leaves plenty of room to be misused. Hence, Storecle is my proposal to let developers rely less on self-discipline and more on tooling and self-restrictive design.\n\n1. To provide an easy way of separating app-wide logic from views i.e.:\n   - No inline: data fetches, transformers, conditionals.\n   - No nested action dispatchers upon other action completion.\n2. To facilitate the action re-usability and modularization.\n3. To provide a gradual path for [React](https://reactjs.org/) developers willing to use [Solid](https://www.solidjs.com/).\n\n## Installation\n\nReact:\n\n```bash\nyarn add @gluecodes/storecle-react\n```\n\nor\n\n```bash\nnpm i @gluecodes/storecle-react\n```\n\nSolid:\n\n```bash\nyarn add @gluecodes/storecle-solid\n```\n\nor\n\n```bash\nnpm i @gluecodes/storecle-solid\n```\n\nIt works along with either [React](https://reactjs.org/) or [Solid](https://www.solidjs.com/) that also needs to be installed in your app. For details, see their own documentations.\n\n## Usage\n\nThis module exports 3 constructs that can be imported for a particular framework in different parts of your app.\n\n```javascript\nimport { builtInActions, PageProvider, useAppContext } from '@gluecodes/storecle-react'\n```\n\nor\n\n```javascript\nimport { builtInActions, PageProvider, useAppContext } from '@gluecodes/storecle-solid'\n```\n\nFor the purpose of the example I used a Solid version.\n\nSoon the official starter templates will be released. Using this library means following certain patterns which are explained below using a simple counter example.\n\n### Mental Model\n\n\u003e See: [Code Sandbox](https://codesandbox.io/s/bold-carlos-tj18g?file=/src/App.js) example for React.\n\n\u003e See: [Code Sandbox](https://codesandbox.io/s/awesome-hertz-jdcgg?file=/src/App.jsx) example for Solid.\n\nFile tree:\n\n```\n.\n├── actions\n│   ├── dataSuppliers (#2)\n│   │   └── dataSuppliers.js\n│   ├── reloadTypes.js (#4)\n│   └── userActions (#3)\n│       └── userActions.js\n├── index.jsx (#1)\n├── Layout.jsx (#5)\n└── partials (#6)\n    └── Counter\n        └── Counter.jsx\n```\n\n#### 1. Page Container\n\nPage provider wraps a given Layout around a single app context.\n\n- `dataSupplierPipeline` - an array providing the order in which Data Suppliers are executed.\n- `dataSuppliers` - an object containing Data Suppliers.\n- `getLayout` - a function which returns the page Layout.\n- `reloadTypes` - an object containing Reload Types.\n- `userActions` - an object containing User Actions.\n- `onError` - a function triggered when an error is thrown either in Data Suppliers or User Actions.\n\n`./index.jsx`\n\n```javascript\nimport { PageProvider } from '@gluecodes/storecle-solid'\n\nimport * as dataSuppliers from './actions/dataSuppliers/dataSuppliers'\nimport * as userActions from './actions/userActions/userActions'\nimport * as reloadTypes from './actions/reloadTypes'\n\nimport Layout from './Layout.jsx'\n\nexport default () =\u003e (\n  \u003cPageProvider\n    dataSupplierPipeline={[dataSuppliers.getTexts, dataSuppliers.getCounter]}\n    dataSuppliers={dataSuppliers}\n    getLayout={() =\u003e Layout}\n    reloadTypes={reloadTypes}\n    userActions={userActions}\n    onError={(err) =\u003e {\n      console.error(err)\n    }}\n  /\u003e\n)\n```\n\n#### 2. Data Suppliers\n\nData suppliers provide data prior to rendering. Note the early returns which demonstrate how to resolve cached data based on Reload Type.\n\n- `builtInActions` - an object containing the following built-in User Actions:\n  - `onStoreChanged` - a function which receives a callback to be triggered when Store changes.\n  - `runUserActions` - a function which allows for executing multiple User Actions at once.\n  - `runDataSuppliers` - a function which receives a Reload Type name. Note that it's exposed to ease the integration with legacy apps. Don't call it manually as Data Suppliers are implicitly reloaded based on the provided Reload Types.\n- Each Data Supplier passes two arguments: `resultOf` and `nameOf`.\n  - `resultOf` - a function providing a result of a given Data Supplier or User Action.\n  - `nameOf` - a function providing a name of either Data Supplier, User Action or Reload Type.\n- Data Suppliers can be either sync or async and write to a central Store by returning/resolving.\n\n`./actions/dataSuppliers/dataSuppliers.js`\n\n```javascript\nimport { builtInActions } from '@gluecodes/storecle-solid'\nimport { reFetchCounter } from '../reloadTypes'\n\nexport function getCounter(resultOf, nameOf) {\n  const reloadType = resultOf(builtInActions.runDataSuppliers)\n  const shouldFetch = reloadType === 'full' || reloadType === nameOf(reFetchCounter)\n\n  if (!shouldFetch) {\n    return resultOf(getCounter)\n  }\n\n  return global.sessionStorage.getItem('appWideCounter') || 0\n}\n\nexport function getTexts(resultOf) {\n  if (resultOf(builtInActions.runDataSuppliers) !== 'full') {\n    return resultOf(getTexts)\n  }\n\n  return {\n    Click: 'Click'\n  }\n}\n```\n\n#### 3. User Actions\n\nActions triggered by a user.\n\n`./actions/userActions/userActions.js`\n\n```javascript\nexport function incrementCounter(counter) {\n  const incrementedCounter = Number(counter) + 1\n\n  global.sessionStorage.setItem('appWideCounter', incrementedCounter)\n}\n```\n\n#### 4. Reload Types\n\nA way to tell the app to re-run Data Suppliers based on executed User Actions.\n\n- A Reload Type groups User Actions together to tell the app to reload all Data Suppliers as a consequence of their execution.\n- When any of its User Actions is triggered, the app sets the Reload Type name under built-in `runDataSuppliers` and reloads all Data Suppliers.\n- Data Suppliers can benefit from caching by early returning their results based on Reload Type name.\n- Each Reload Type is a function which passes `nameOf` and returns an array of User Action names.\n  - `nameOf` - a function providing a name of User Action.\n\n`./actions/reloadTypes.js`\n\n```javascript\nimport { incrementCounter } from './userActions/userActions'\n\nexport const reFetchCounter = (nameOf) =\u003e [nameOf(incrementCounter)]\n```\n\n#### 5. Layout\n\nNothing else than the page layout.\n\n`./Layout.jsx`\n\n```jsx\nimport Counter from './partials/Counter/Counter.jsx'\n\nexport default () =\u003e (\n  \u003c\u003e\n    \u003cCounter /\u003e\n  \u003c/\u003e\n)\n```\n\n#### 6. Partials\n\nPartials are self-contained pieces of UI which have access to app state via the app context.\n\n- `useAppContext` - a function which returns an array of 3 items: `resultOf`, `action`, `nameOf`.\n  - `resultOf` - a function providing a result of a given Data Supplier or User Action.\n  - `action` - a function which triggers User Action.\n  - `nameOf` - a function providing a name of either Data Supplier or User Action.\n\n`./partials/Counter/Counter.jsx`\n\n```jsx\nimport { useAppContext } from '@gluecodes/storecle-solid'\n\nimport { getCounter, getTexts } from '../../actions/dataSuppliers/dataSuppliers'\nimport { incrementCounter } from '../../actions/userActions/userActions'\n\nexport default () =\u003e {\n  const [resultOf, action] = useAppContext()\n\n  return (\n    \u003cbutton\n      onClick={() =\u003e {\n        action(incrementCounter)(resultOf(getCounter))\n      }}\n    \u003e\n      {resultOf(getTexts)?.Click}: {resultOf(getCounter)}\n    \u003c/button\u003e\n  )\n}\n```\n\n## Documentation\n\nWIP, so far there is only this `README.md` and a project `./test/env`. More docs will come with starter templates and CLI tooling.\n\n## License\n\n[MIT](https://github.com/gluecodes/storecle/blob/master/LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgluecodes%2Fstorecle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgluecodes%2Fstorecle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgluecodes%2Fstorecle/lists"}