{"id":13727276,"url":"https://github.com/web-ridge/react-ridge-state","last_synced_at":"2025-04-05T05:03:46.679Z","repository":{"id":42775129,"uuid":"264024103","full_name":"web-ridge/react-ridge-state","owner":"web-ridge","description":"Simple 💪 fast ⚡️ and small :balloon: (400 bytes) global state management for React (Native)","archived":false,"fork":false,"pushed_at":"2023-01-07T04:47:34.000Z","size":612,"stargazers_count":223,"open_issues_count":6,"forks_count":11,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-03-29T04:05:13.821Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/react-ridge-state","language":"TypeScript","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/web-ridge.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-14T21:00:51.000Z","updated_at":"2024-08-01T02:40:21.000Z","dependencies_parsed_at":"2023-02-06T12:16:02.906Z","dependency_job_id":null,"html_url":"https://github.com/web-ridge/react-ridge-state","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/web-ridge%2Freact-ridge-state","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/web-ridge%2Freact-ridge-state/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/web-ridge%2Freact-ridge-state/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/web-ridge%2Freact-ridge-state/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/web-ridge","download_url":"https://codeload.github.com/web-ridge/react-ridge-state/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247289409,"owners_count":20914464,"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":[],"created_at":"2024-08-03T01:03:47.580Z","updated_at":"2025-04-05T05:03:46.661Z","avatar_url":"https://github.com/web-ridge.png","language":"TypeScript","funding_links":["https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick\u0026hosted_button_id=7B9KKQLXTEW9Q\u0026source=url"],"categories":["TypeScript"],"sub_categories":[],"readme":"# react-ridge-state :weight_lifting_woman: ⚡️ :weight_lifting_man:\n\n![Bundle Size](https://badgen.net/bundlephobia/minzip/react-ridge-state) [![npm version](https://badge.fury.io/js/react-ridge-state.svg)](https://badge.fury.io/js/react-ridge-state) ![npm](https://img.shields.io/npm/dt/react-ridge-state.svg)\n\n**Simple** :muscle: **fast** ⚡️ and **small** :balloon: (400 bytes) global state management for React which can be used outside of a React component too!\n\n```\nyarn add react-ridge-state\n```\n\nor\n\n```\nnpm install react-ridge-state --save\n```\n\n## Why another state library :thinking:\n\nWe were frustrated that the current solutions could often only be used from React or have too complicated APIs. We wanted a lightweight solution with a smart API that can also be used outside React components.\n\n## Features :woman_juggling:\n\n- React / React Native\n- Simple\n- Fast\n- Very tiny (400 bytes)\n- 100% Typesafe\n- Hooks\n- Use outside React components\n- Custom selectors for deep state selecting\n\n## About us\nWe want developers to be able to build software faster using modern tools like GraphQL, Golang and React Native.\n\nGive us a follow on Twitter:\n[RichardLindhout](https://twitter.com/RichardLindhout),\n[web_ridge](https://twitter.com/web_ridge)\n\n## Donate\nPlease contribute or donate so we can spend more time on this library\n\n[Donate with PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick\u0026hosted_button_id=7B9KKQLXTEW9Q\u0026source=url)\n\n\n## Getting started :clap: :ok_hand:\n\n### Create a new state\n\n```typescript\nimport { newRidgeState } from \"react-ridge-state\";\n\ninterface CartProduct {\n  id: number;\n  name: string;\n}\n\nexport const cartProductsState = newRidgeState\u003cCartProduct[]\u003e([\n  { id: 1, name: \"Product\" },\n]);\n```\n\n### Use state inside components\n\n```typescript\nimport { cartProductsState } from \"../cartProductsState\";\n\n// same interface and usage as setState\nconst [cartProducts, setCartProducts] = cartProductsState.use();\n\n// if you only need the value and no setState\nconst cartProducts = cartProductsState.useValue();\n\n// if you only want to subscribe to part of your state (this example the first product)\nconst cartProducts = cartProductsState.useSelector((state) =\u003e state[0]);\n\n// custom comparison function (only use this if you have heavy child components and the default === comparison is not sufficient enough)\nconst cartProducts = cartProductsState.useSelector(\n  (state) =\u003e state[0],\n  (a, b) =\u003e JSON.stringify(a) === JSON.stringify(b)\n);\n```\n\n### Supported functions outside of React\nThe following functions work outside of React e.g. in your middleware but you can also use them in your component.\n\n```typescript\nimport { cartProductsState } from \"../cartProductsState\";\n\n// get the root state\ncartProductsState.get();\n\n// set the state directly\ncartProductsState.set([{ id: 1, name: \"NiceProduct\" }]);\n\n// if you want previous state as callback\ncartProductsState.set((prevState) =\u003e [\n  ...prevState,\n  { id: 1, name: \"NiceProduct\" },\n]);\n\n// you can also use a callback so you know when state has rendered\ncartProductsState.set(\n  (prevState) =\u003e [...prevState, { id: 1, name: \"NiceProduct\" }],\n  (newState) =\u003e {\n    console.log(\"New state is rendered everywhere\");\n  }\n);\n\n// you can reset to initial state too\ncartProductsState.reset()\n\n// you can also subscribe to state changes outside React\n\nconst unsubscribe = cartProductsState.subscribe((newState, oldState) =\u003e {\n  console.log(\"State changed\");\n});\n\n// call the returned unsubscribe function to unsubscribe.\nunsubscribe();\n```\n\n### Example\n\n```tsx\n// CartState.ts\nimport { newRidgeState } from \"react-ridge-state\";\n\n// this can be used everywhere in your application\nexport const globalCounterState = newRidgeState\u003cnumber\u003e(0); // 0 could be something else like objects etc. you decide!\n\n// Counter.tsx\nfunction Counter() {\n  // you can use these everywhere in your application the globalCounterState will update automatically  even if set globally\n  const [count, setCount] = globalCounterState.use();\n  return (\n    \u003cdiv\u003e\n      \u003cdiv\u003eCount: {count}\u003c/div\u003e\n      \u003cbutton onClick={() =\u003e setCount(count + 1)}\u003eAdd 1\u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n\n// CounterViewer.tsx\nfunction CounterViewer() {\n  // you can use these everywhere in your application the globalCounterState will update automatically even if set globally\n  const counter = globalCounterState.useValue();\n\n  return (\n    \u003cdiv\u003e\n      \u003cdiv\u003eCount: {counter}\u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Usage in class components\n\nSince we want to keep this library small we are not supporting class components but you could use wrappers like this if you have class components, however we would recommend to use functional components since they are more type safe and easier to use.\n\n```tsx\n\nclass YourComponentInternal extends Component {\n  render() {\n    \u003cdiv\u003e\n      \u003cdiv\u003eCount: {this.props.count}\u003c/div\u003e\n      \u003cbutton onClick={() =\u003e this.props.setCount(count + 1)}\u003eAdd 1\u003c/button\u003e\n    \u003c/div\u003e\n  }\n}\n\nexport default function YourComponent(props) {\n  const [count, setCount] = globalCounterState.use();\n  return \u003cYourComponentInternal {...props} count={count} setCount={setCount}\u003e\n}\n```\n\n### Persistence example\n\nIt's possible to add make your state persistent, you can use storage library you desire. \nlocalStorage is even simpler since you don't need async functions\n\n```typescript\nconst authStorageKey = \"auth\";\nconst authState = newRidgeState\u003cAuthState\u003e(\n  { loading: true, token: \"\" },\n  {\n    onSet: async (newState) =\u003e {\n      try {\n        await AsyncStorage.setItem(\"@key\", JSON.stringify(newState));\n      } catch (e) {}\n    },\n  }\n);\n\n// setInitialState fetches data from localStorage\nasync function setInitialState() {\n  try {\n    const item = await AsyncStorage.getItem(\"@key\");\n    if (item) {\n      const initialState = JSON.parse(item);\n      authState.set(initialState);\n    }\n  } catch (e) {}\n}\n\n// run function as application starts\nsetInitialState();\n```\n\n### Managing complex/nested state with Immer\n\nSometimes you might need to update values that are deeply nested, code for this can end up looking verbose as you will likely need to use many spread operators. A small utility library called [Immer](https://github.com/immerjs/immer) can help simplify things.\n\n```tsx\nconst characterState = newRidgeState\u003cCharacterState\u003e({\n  gold: 100,\n  stats: {\n    spells: {\n      fire: 10,\n      watter: 10\n    },\n    battle: {\n      health: 100,\n      mana: 100\n    },\n    profession: {\n      mining: 10,\n      herbalism: 10\n    }\n  }\n})\n\n// Update mana and herbalism without immer\ncharacterState.set(previous =\u003e ({\n  ...previous,\n  stats: {\n    ...previous.stats,\n    battle: {\n      ...previous.stats.battle,\n      mana: 200\n    },\n    profession: {\n      ...previous.stats.profession,\n      herbalism: 20\n    }\n  }\n}))\n\n// Update mana and herbalism using immer\nimport { produce } from \"immer\";\n\ncharacterState.set(previous =\u003e\n  produce(previous, updated =\u003e {\n    updated.stats.battle.mana = 200\n    updated.stats.profession.herbalism = 20\n  })\n)\n```\n\n\n## Testing your components which use react-ridge-state\n\nYou can find examples of testing components with global state here:\nhttps://github.com/web-ridge/react-ridge-state/blob/main/src/tests/Counter.test.tsx\n\n### Jest\nJest keeps the global state between tests in one file. \nTests inside one file run synchronous by default, so no racing can occur. \n   \nWhen testing in different files (test1.test.js, test2.test.js), the global state is new for every file. \nYou don't have to mock or reset the state even if the tests run in parallel.\n\n### Mocha\n\nIn Mocha you will need to reset the state the initial value before each test since the state is shared across all tests.\nYou could do that with the code below and **not** using the --parallel mode of Mocha.\n\n```tsx\nbeforeEach(()=\u003e {\n    characterState.reset()\n})\n```\n\n### Checkout our other libraries\n- Simple form library for React Native with great UX for developer and end-user [react-native-use-form](https://github.com/web-ridge/react-native-use-form)\n- Smooth and fast cross platform Material Design date and time picker for React Native Paper: [react-native-paper-dates](https://github.com/web-ridge/react-native-paper-dates)\n- Smooth and fast cross platform Material Design Tabs for React Native Paper: [react-native-paper-tabs](https://github.com/web-ridge/react-native-paper-tabs)\n- Simple translations in React (Native): [react-ridge-translations](https://github.com/web-ridge/react-ridge-translations)\n- 1 command utility for React Native (Web) project: [create-react-native-web-application](https://github.com/web-ridge/create-react-native-web-application)\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fweb-ridge%2Freact-ridge-state","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fweb-ridge%2Freact-ridge-state","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fweb-ridge%2Freact-ridge-state/lists"}