{"id":13511349,"url":"https://github.com/yamalight/outstated","last_synced_at":"2025-09-24T22:30:56.662Z","repository":{"id":141735813,"uuid":"156871132","full_name":"yamalight/outstated","owner":"yamalight","description":"Simple hooks-based state management for React","archived":false,"fork":false,"pushed_at":"2020-01-12T10:11:10.000Z","size":246,"stargazers_count":107,"open_issues_count":0,"forks_count":7,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-11-01T13:34:41.398Z","etag":null,"topics":["hooks","management","react","react-hooks","state"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yamalight.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-11-09T14:13:29.000Z","updated_at":"2023-03-15T17:11:56.000Z","dependencies_parsed_at":null,"dependency_job_id":"aabe7456-ace7-4d9e-9550-4be02ae88b04","html_url":"https://github.com/yamalight/outstated","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yamalight%2Foutstated","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yamalight%2Foutstated/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yamalight%2Foutstated/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yamalight%2Foutstated/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yamalight","download_url":"https://codeload.github.com/yamalight/outstated/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234131312,"owners_count":18784416,"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":["hooks","management","react","react-hooks","state"],"created_at":"2024-08-01T03:00:48.012Z","updated_at":"2025-09-24T22:30:56.288Z","avatar_url":"https://github.com/yamalight.png","language":"JavaScript","funding_links":[],"categories":["react","JavaScript","List"],"sub_categories":[],"readme":"# Outstated\n\n\u003e Simple hooks-based state management for React\n\n[![Build Status](https://travis-ci.com/yamalight/outstated.svg?branch=master)](https://travis-ci.com/yamalight/outstated)\n[![Coverage Status](https://coveralls.io/repos/github/yamalight/outstated/badge.svg?branch=master)](https://coveralls.io/github/yamalight/outstated?branch=master)\n[![Minzip Size](https://img.shields.io/bundlephobia/minzip/outstated.svg?style=flat)](https://www.npmjs.com/package/outstated)\n[![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://opensource.org/licenses/MIT)\n\nLike [unstated](https://github.com/jamiebuilds/unstated) but with hooks\n\n## Installation\n\n```sh\nnpm install outstated\n```\n\n## Example\n\n```jsx\nimport React, {useState} from 'react';\nimport ReactDOM from 'react-dom';\nimport {Provider, useStore} from 'outstated';\n\nconst store = () =\u003e {\n  const [count, setCount] = useState(0);\n\n  const increment = () =\u003e setCount(count + 1);\n  const decrement = () =\u003e setCount(count - 1);\n  const reset = () =\u003e setCount(0);\n\n  return {count, increment, decrement, reset};\n};\n\nfunction Counter() {\n  const {count, increment, decrement, reset} = useStore(store);\n\n  return (\n    \u003cdiv\u003e\n      \u003cbutton onClick={decrement}\u003e-\u003c/button\u003e\n      \u003cspan\u003e{count}\u003c/span\u003e\n      \u003cbutton onClick={increment}\u003e+\u003c/button\u003e\n      \u003cbutton onClick={reset}\u003ereset\u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n\nReactDOM.render(\n  \u003cProvider stores={[store]}\u003e\n    \u003cCounter /\u003e\n  \u003c/Provider\u003e,\n  document.getElementById('root')\n);\n```\n\nFor more examples, see the `example/` directory.\n\n## Guide\n\n[Unstated](https://github.com/jamiebuilds/unstated) is awesome, but doesn't really use hooks.  \nCan we build something similar to unstated with hooks to make something even nicer?\n\n### Introducing Outstated\n\nI really like unstated. I really like hooks.\nI wanted a simple hook-based app state management solution.\nThis is why I've built Outstated.\n\nOutstated is built on top of React hooks, context\nand patterns surrounding those elements.\n\nIt has three pieces:\n\n##### `Store`\n\nIt's a place to store our state and some of the logic for updating it.\n\nStore is a very simple React hook (which means you can re-use it, use other hooks within it, etc).\n\n```js\nimport {useState} from 'React';\n\nconst store = () =\u003e {\n  const [state, setState] = useState({test: true});\n\n  const update = val =\u003e setState(val);\n\n  return {state, update};\n};\n```\n\nNote that stores use `useState` hook from React for managing state.\nWhen you call `setState` it triggers components to re-render,\nso be careful not to mutate `state` directly or your components won't re-render.\n\n##### `useStore`\n\nNext we'll need a piece to introduce our state back into the tree so that:\n\n- When state changes, our components re-render.\n- We can depend on our store state.\n- We can call functions exposed by the store.\n\nFor this we have the `useStore` hook which allows us to get global store instances\nby using specific store constructor.\n\n```jsx\nfunction Counter() {\n  const {count, decrement, increment} = useStore(counterStore);\n\n  return (\n    \u003cdiv\u003e\n      \u003cspan\u003e{count}\u003c/span\u003e\n      \u003cbutton onClick={decrement}\u003e-\u003c/button\u003e\n      \u003cbutton onClick={increment}\u003e+\u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n##### `\u003cProvider\u003e`\n\nThe final piece that Outstated has is `\u003cProvider\u003e` component.\nIt has two roles:\n\n1. It initializes global instances of given stores (this is required because React expects the number of hooks to be consistent across re-renders)\n2. It uses a set of contexts to pass initialized instances of given stores to all the components down the tree.  \n   Different context is used for each store. This allows to only trigger re-renders in the components that use the updated store. As a (minor) downside of this approach - nested contexts are created for each store you pass.\n\n```jsx\nrender(\n  \u003cProvider stores={[counterStore]}\u003e\n    \u003cCounter /\u003e\n  \u003c/Provider\u003e\n);\n```\n\n### Testing\n\nWhenever we consider the way that we write the state in our apps we should be\nthinking about testing.  \nWe want to make sure that our state containers have a clean way to test them.\n\nBecause our containers are just hooks, we can construct them in\ntests and assert different things about them very easily.\n\n```js\nimport {renderHook, act} from 'react-hooks-testing-library';\n\ntest('counter', async () =\u003e {\n  let count, increment, decrement;\n  renderHook(() =\u003e ({count, increment, decrement} = counterStore()));\n\n  expect(count).toBe(0);\n\n  act(() =\u003e increment());\n  expect(count).toBe(1);\n\n  act(() =\u003e decrement());\n  expect(count).toBe(0);\n});\n```\n\n## Related\n\n- [Unstated](https://github.com/jamiebuilds/unstated)\n- [React hooks](https://reactjs.org/docs/hooks-intro.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyamalight%2Foutstated","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyamalight%2Foutstated","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyamalight%2Foutstated/lists"}