{"id":18833575,"url":"https://github.com/ibitcy/react-stores","last_synced_at":"2025-04-14T04:31:58.622Z","repository":{"id":17137830,"uuid":"81196223","full_name":"ibitcy/react-stores","owner":"ibitcy","description":"Shared states for React and React Native","archived":false,"fork":false,"pushed_at":"2023-09-04T10:47:40.000Z","size":4084,"stargazers_count":38,"open_issues_count":14,"forks_count":10,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-11T14:58:31.494Z","etag":null,"topics":["flux","persistence","react","react-stores","reactive","states","store","storestate"],"latest_commit_sha":null,"homepage":"","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/ibitcy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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}},"created_at":"2017-02-07T10:29:44.000Z","updated_at":"2023-11-30T06:56:46.000Z","dependencies_parsed_at":"2024-06-20T23:26:19.037Z","dependency_job_id":"fe50911f-631d-444a-a34a-750d7664a81e","html_url":"https://github.com/ibitcy/react-stores","commit_stats":{"total_commits":329,"total_committers":15,"mean_commits":"21.933333333333334","dds":0.7173252279635258,"last_synced_commit":"e864f8d0889c4e53212f09802551921fa9b1dd27"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ibitcy%2Freact-stores","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ibitcy%2Freact-stores/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ibitcy%2Freact-stores/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ibitcy%2Freact-stores/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ibitcy","download_url":"https://codeload.github.com/ibitcy/react-stores/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248821797,"owners_count":21166957,"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":["flux","persistence","react","react-stores","reactive","states","store","storestate"],"created_at":"2024-11-08T02:01:32.143Z","updated_at":"2025-04-14T04:31:57.654Z","avatar_url":"https://github.com/ibitcy.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-stores\n\n![react-stores](https://ibitcy.github.io/react-stores/react-stores.svg)\n\n[![build status](https://badgen.net/travis/ibitcy/react-stores?icon=travis)](https://travis-ci.org/ibitcy/react-stores)\n[![npm bundlephobia minzip](https://badgen.net/bundlephobia/minzip/react-stores@latest?icon=awesome)\n![npm version](https://badgen.net/npm/v/react-stores?icon=npm\u0026color=blue)](https://www.npmjs.com/package/react-stores)\n![with types](https://badgen.net/badge/1/typescript/007acc?icon=typescript)\n[![devtool extension](https://badgen.net/badge/1/devtool%20extension/cyan?icon=chrome\u0026label)](https://github.com/ibitcy/react-stores-devtools-extension)\n\nShared states for React.\n\n## How to install\n\n```shell\nnpm i react-stores --save\n```\n\n## Demo\n\n[Online demo](https://ibitcy.github.io/react-stores/)\n\nFor local demo clone this repo and run the script below inside the dir, then go to [http://localhost:9000](http://localhost:9000) in your browser\n\n```bash\nnpm i \u0026\u0026 npm run demo\n```\n\n## Tests\n\n```bash\nnpm run test\n```\n\n## How to use\n\nHere you are a few examples\n\n### Create a Store\n\n```typescript\n// myStore.ts\nimport { Store } from 'react-stores';\n\nexport interface IMyStoreState {\n  counter: number;\n}\n\nexport const myStore = new Store\u003cIMyStoreState\u003e({\n  counter: 0, // initial state values\n});\n```\n\n### React useHooks\n\n```typescript jsx\nimport React, { FC } from 'react';\nimport { useStore } from 'react-stores';\nimport { myStore } from './myStore';\n\nexport const Component: FC = () =\u003e {\n  const myStoreState = useStore(myStore);\n\n  return (\n    \u003cdiv\u003e\n      {myStoreState.counter}\n    \u003cdiv/\u003e\n  );\n}\n\n// Invoke this code somewhere outside Component and it will be re-rendered\nmyStore.setState({\n  counter: 2,\n});\n```\n\nLook here 👉[more about use hooks](#use-includekeys-in-usestore)\n\n### Event-driven component\n\n```typescript jsx\n// EventDrivenComponent.tsx\nimport React from 'react';\nimport { StoreEvent, StoreEventType } from 'react-stores';\nimport { myStore, IMyStoreState } from './myStore';\n\ninterface State {\n  myStoreState: IMyStoreState;\n}\n\nexport class EventDrivenComponent extends React.Component\u003cany, State\u003e {\n  private storeEvent: StoreEvent\u003cIMyStoreState\u003e = null;\n\n  state: State = {\n    myStoreState: myStore.state,\n  };\n\n  comonentDidMount() {\n    // Add store state event binder\n    this.storeEvent = myStore.on(\n      StoreEventType.All,\n      (storeState: IMyStoreState, prevState: IMyStoreState, type: StoreEventType) =\u003e {\n        this.setState({\n          myStoreState: storeState,\n        });\n      },\n    );\n  }\n\n  componentDidUnmount() {\n    // Remove store state event binder\n    this.storeEvent.remove();\n  }\n\n  render() {\n    return \u003cp\u003eCounter: {this.state.myStoreState.counter.toString()}\u003c/p\u003e;\n  }\n}\n```\n\n### Component with followStore decorator\n\n```typescript jsx\n// FollowStoreComponent.tsx\nimport React from 'react';\nimport { followStore } from 'react-stores';\nimport { myStore } from './myStore';\n\n// You can use multiple follows\n// @followStore(myStore)\n// @followStore(myOtherStore)\n@followStore(myStore)\nexport class CounterDecorator extends React.Component {\n  public render() {\n    return \u003cp\u003eCounter: {myStore.state.counter.toString()}\u003c/p\u003e;\n  }\n}\n```\n\n### Advanced Component Hooks\n\n```typescript jsx\nimport React from 'react';\nimport { useStore } from 'react-stores';\nimport { myStore, IMyStoreState } from './myStore';\n\ninterface IMappedState {\n  counter: string;\n}\n\ninterface IProps {\n  index: number;\n}\n\nfunction recursiveFibonacci(num: number) {\n  if (num \u003c= 1) {\n    return 1;\n  }\n  return recursiveFibonacci(num - 1) + recursiveFibonacci(num - 2);\n}\n\nexport const MyHookComponent: React.FC\u003cIProps\u003e = (props: IProps) =\u003e {\n  // Memoize your mapState function\n  const mapState = React.useCallback(\n    (state: IMyStoreState): IMappedState =\u003e ({\n      counter: recursiveFibonacci(state.counter), // Very long operation\n    }),\n    [props.index],\n  );\n\n  // Get your state form store\n  const { counter } = useStore\u003cIMyStoreState, IMappedState\u003e(myStore, mapState);\n\n  return \u003cp\u003eCounter: {counter}\u003c/p\u003e;\n};\n```\n\n### Mutating store state\n\n```typescript\nimport { myStore } from './myStore';\n\nmyStore.setState({\n  counter: 9999,\n});\n```\n\n### Read store state value\n\n```typescript\nimport { myStore } from './myStore';\n\nconsole.log(myStore.state.counter); // 9999\n```\n\n### useIsolatedStore\n\n```typescript tsx\nimport React, { FC } from 'react';\nimport { useIsolatedStore } from 'react-stores';\n\ninterface IMyStoreState {\n  counter: number;\n}\n\nconst initialState = {\n  counter: 0,\n};\n\nexport const Component: FC\u003c{ name: sting }\u003e = ({ name }) =\u003e {\n  const myStore = useIsolatedStore\u003cIMyStoreState\u003e(initialState, {\n    persistence: true,\n    immutable: true,\n    name,\n  });\n\n  const handleIncrement = React.useCallback(() =\u003e {\n    myStore.setState({\n      counter: myStore.state.counter + 1,\n    });\n  }, [myStore.state.counter]);\n\n  return \u003cbutton onClick={handleIncrement}\u003e{myStore.state.counter}\u003c/button\u003e;\n};\n```\n\n# API\n\n### Store\n\n#### Store constructor\n\n| Argument            | Type                                                                                                                   | Optional | Description                                                                                                                           |\n| ------------------- | ---------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |\n| `initialState`      | [`StoreState`](#storestate)                                                                                            | No       | Initial state values object                                                                                                           |\n| `options`           | [`StoreOptions`](#storeoptions)                                                                                        | Yes      | Setup store as you need with immutable, persistence and etс.                                                                          |\n| `persistenceDriver` | [`StorePersistentDriver\u003cStoreState\u003e`](https://github.com/ibitcy/react-stores/blob/master/src/StorePersistentDriver.ts) | Yes      | [`StorePersistentDriver\u003cStoreState\u003e`](https://github.com/ibitcy/react-stores/blob/master/src/StorePersistentDriver.ts) class instance |\n\n[Example](#create-a-store)\n\n#### StoreState\n\nThis can be any interface describes your store's state.\n\n#### initialState\n\nAny object corresponding to StoreState interface.\n\n#### StoreOptions\n\n| Property          | Type      | Default | Optional | Description                                                                                                                                                                                                                                     |\n| ----------------- | --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `immutable`       | `boolean` | `false` | Yes      | Object.freeze(...) for store state instances, when disabled you have fully mutable states, but increased performance, [for more see](https://ibitcy.github.io/react-stores/?#Performance)                                                       |\n| `persistence`     | `boolean` | `false` | Yes      | Enables persistent mode using LocalStorage persistence of custom StorePersistentDriver. If you want use two persistence stores with identical interface you must set `name` props. In other case both of stores will be use one key in storage. |\n| `name`            | `string`  | null    | Yes      | Uses for name in storage if persistence flag is true. If name not defined name for persistent will be created from initialState interface.                                                                                                      |\n| `setStateTimeout` | `number`  | `0`     | Yes      | Store state updates with timeout                                                                                                                                                                                                                |\n\n#### Store methods\n\n[Check demo here](https://ibitcy.github.io/react-stores/?#Snapshots).\n\n| Method name        | Arguments                                         | Returns                                 | Description                                                                                |\n| ------------------ | ------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------ |\n| `setState`         | `newState: Partial\u003cStoreState\u003e`                   | `void`                                  | Set store's state to provided new one can be partial                                       |\n| `resetState`       | No                                                | `void`                                  | Reset srote to it's `initialState`                                                         |\n| `update`           | No                                                | `void`                                  | Force update all bound components and emit events                                          |\n| `on`               | eventType, callback\\* [+2overload](#on-overloads) | [`StoreEvent\u003cStoreState\u003e`](#storeevent) | Subscribe to store state event listener                                                    |\n| `resetPersistence` | No                                                | `void`                                  | Reset persistent state                                                                     |\n| `resetDumpHistory` | No                                                | `void`                                  | Reset all persistent history states                                                        |\n| `saveDump`         | No                                                | `number`                                | Save state dump and get its ID which is represented in number of current time milliseconds |\n| `removeDump`       | `timestamp: number`                               | `void`                                  | Remove state dump by ID                                                                    |\n| `restoreDump`      | `timestamp: number`                               | `void`                                  | Replace current state to one from history by ID                                            |\n| `getDumpHistory`   | No                                                | `number[]`                              | Get dump history IDs                                                                       |\n\n##### \\* Store methods: `on()` arguments\n\n##### `on()` overloads\n\n```typescript\n// Use this to get the whole store state\neventType: StoreEventType | StoreEventType[],\ncallback: (storeState: StoreState, prevState: StoreState, type: StoreEventType) =\u003e void\n```\n\nUse this overload if you need some [optimization](#use-includekeys-in-storeevent).\n\n```typescript\n// Use this to get only specific keys\neventType: StoreEventType | StoreEventType[],\nincludeKeys: Array\u003ckeysof StoreState\u003e\ncallback: (storeState: StoreState, prevState: StoreState, includeKeys: Array\u003ckeysof StoreState\u003e, type: StoreEventType) =\u003e void\n```\n\n### StoreEvent\n\n#### StoreEvent methods\n\n| Method name | Arguments | Returns | Description                                 |\n| ----------- | --------- | ------- | ------------------------------------------- |\n| `remove`    | No        | `void`  | Unsubscribe from store state event listener |\n\n#### StoreEventType Enum\n\n| Value         | The event will be emitted                           |\n| ------------- | --------------------------------------------------- |\n| `All`         | After every other event type emits                  |\n| `Init`        | Once, as soon as the event has been bound           |\n| `Update`      | Each time after store was updated                   |\n| `DumpUpdated` | Each time after persistent store's dump was updated |\n\n[Example](#event-driven-component)\n\n### followStore\n\n_We do not recomend use this way to connected with your stores, because it have no any performance techniques_\n\n| Argument | Type                          | Optional | Description    |\n| -------- | ----------------------------- | -------- | -------------- |\n| `store`  | [`Store\u003cStoreState\u003e`](#store) | No       | followed store |\n\n[Example](#component-with-followstore-decorator)\n\n### useStore\n\nUse useStore only with `store` argument makes many performance issues.\nInstead, we recommend using [includeKeys](#use-includekeys-in-usestore) or [mapState](#use-mapstate-in-usestore) for optimizations and custom [compare](#use-compare-in-usestore) for perfect optimization.\n\n| Argument    | Type                                                                                     | Optional | Description                                                                                                                                                        |\n| ----------- | ---------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `store`     | [`Store\u003cStoreState\u003e`](#store)                                                            | No       | followed store\\*                                                                                                                                                   |\n| `eventType` | [`StoreEventType`](#storeeventtype-enum) `\\|` [`StoreEventType[]`](#storeeventtype-enum) | Yes      | re-render only on specific events                                                                                                                                  |\n| `mapState`  | [`callback`](#mapState)                                                                  | Yes      | The selector function should be pure since it is potentially executed multiple times and at arbitrary points in time.                                              |\n| `compare`   | [`callback`](#compare)                                                                   | Yes      | The optional comparison function also enables using something like Lodash's \\_.isEqual() or Immutable.js's comparison capabilities. More about [compare](#compare) |\n\n##### \\* To have more control over re-renders use eventType, mapState and compare their arguments. See more in [optimization](#optimization).\n\n```typescript jsx\nimport React from 'react';\nimport { useStore } from 'react-stores';\nimport { myStore } from './myStore';\n\nexport const CounterComponent = ({ value }) =\u003e {\n  const store = useStore(myStore);\n\n  // Do not abuse this in a real app with complicated stores.\n  // The component will not automatically update if the myStore state changes.\n  return \u003cdiv\u003e{store.anyOfProps}\u003c/div\u003e;\n};\n```\n\nWith `includeKeys`. [example](#use-includekeys-in-usestore).\n\n| Argument      | Type                                                                                     | Optional | Description                       |\n| ------------- | ---------------------------------------------------------------------------------------- | -------- | --------------------------------- |\n| `store`       | [`Store\u003cStoreState\u003e`](#store)                                                            | No       | followed store                    |\n| `includeKeys` | `Array\u003ckeyof StoreState\u003e`                                                                | No       | followed keys from store          |\n| `eventType`   | [`StoreEventType`](#storeeventtype-enum) `\\|` [`StoreEventType[]`](#storeeventtype-enum) | Yes      | re-render only on specific events |\n\nOr with [`mapState`](#mapState) and [`compare`](#compare) only. [Example](#use-mapstate-in-usestore).\n\n| Argument   | Type                    | Optional | Description                                                                                                                                                        |\n| ---------- | ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `store`    | `Store\u003cStoreState\u003e`     | No       | followed store                                                                                                                                                     |\n| `mapState` | [`callback`](#mapState) | No       | The selector function should be pure since it is potentially executed multiple times and at arbitrary points in time.                                              |\n| `compare`  | [`callback`](#compare)  | Yes      | The optional comparison function also enables using something like Lodash' `_.isEqual()` or Immutable.js's comparison capabilities. More about [compare](#compare) |\n\nOr use with second argument called options (legacy).\n\n| Argument  | Type                          | Optional | Description                                  |\n| --------- | ----------------------------- | -------- | -------------------------------------------- |\n| `store`   | `Store\u003cStoreState\u003e`           | No       | followed store                               |\n| `options` | [`Object`](#usestore-options) | No       | legacy, use an another [overload](#usestore) |\n\n#### useStore options\n\nThis is legacy, please use another useState overload.\n\n| Argument    | Type                                                                                     | Optional | Description                                                                                                                                                        |\n| ----------- | ---------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `eventType` | [`StoreEventType`](#storeeventtype-enum) `\\|` [`StoreEventType[]`](#storeeventtype-enum) | Yes      | re-render only on specific events                                                                                                                                  |\n| `mapState`  | [`callback`](#mapState)                                                                  | Yes      | The selector function should be pure since it is potentially executed multiple times and at arbitrary points in time.                                              |\n| `compare`   | [`callback`](#compare)                                                                   | Yes      | The optional comparison function also enables using something like Lodash's \\_.isEqual() or Immutable.js's comparison capabilities. More about [compare](#compare) |\n\n#### mapState\n\nThis should take the first argument called state, optionally the second argument called prevState, and also takes optionally `type` as the third argument and returns a plain object containing data that connected component(s) listens to. Selector function should be pure since it is potentially executed multiple times and at arbitrary points in time.\n\n```typescript\ntype TMapState\u003cStoreState, MappedState\u003e = (\n  storeState: StoreState,\n  prevState?: StoreState,\n  type?: StoreEventType,\n) =\u003e MappedState;\n```\n\n#### compare\n\nWhen store changes, useState() with `mapState` calling a `compare` of the previous `mapState` result value and the current result value. If they are different, the component will be forced to re-render. If they are the same, the component will not re-render. It should return `true` if compared states are equal. By default, it uses strict `===` reference equality checks for next and previous mapped state. It works only if you map primitives. Check this [compare](#use-compare-in-usestore) explanation.\n\n```typescript\ntype TCompare\u003cMappedState\u003e = (storeMappedState: MappedState, prevStoreMappedState: MappedState) =\u003e boolean;\n```\n\n### useIsolatedStore\n\nIf you want to use isolated persistent stores dynamically with identical interface you must set `name` property inside passed options. In other case both of stores will be use one key in storage. [Check demo here](https://ibitcy.github.io/react-stores/?#Isolated).\n\n| Argument            | Type                                                                                                                   | Optional | Description                                                                                                                           |\n| ------------------- | ---------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |\n| `initialState`      | [`StoreState`](#storestate)                                                                                            | No       | Initial state values object                                                                                                           |\n| `options`           | [`StoreOptions`](#storeoptions)                                                                                        | Yes      | Setup store as you need with immutable, persistence and etс.                                                                          |\n| `persistenceDriver` | [`StorePersistentDriver\u003cStoreState\u003e`](https://github.com/ibitcy/react-stores/blob/master/src/StorePersistentDriver.ts) | Yes      | [`StorePersistentDriver\u003cStoreState\u003e`](https://github.com/ibitcy/react-stores/blob/master/src/StorePersistentDriver.ts) class instance |\n\n# Persistence\n\nA store instance can be persistent from session to session in case you've provided [`StorePersistentDriver`](https://github.com/ibitcy/react-stores/blob/master/src/StorePersistentDriver.ts) to it. React-stores includes built-in `StorePersistentLocalStorageDriver`, it saves store state into the LocalStore\\* using `name` or generated hash-name based on initialState interface. [Check demo here](https://ibitcy.github.io/react-stores/?#Persistent).\n\n\\* For React Native you have to provide your own `StorePersistentDriver` see below.\n\n```typescript\nconst myStore = new Store\u003cIMyStoreState\u003e(initialState, new StorePersistentLocalStorageDriver('myStore'));\n```\n\nYou can implement your own persistence driver by implementing [`StorePersistentDriver`](https://github.com/ibitcy/react-stores/blob/master/src/StorePersistentDriver.ts) abstract class.\n\n# Optimization\n\nIf you need to solve performance problems in the Components connected to stores, react-stores offers you tools to help you fix performance issues. [Check demo here](https://ibitcy.github.io/react-stores/?#optimization).\n\n### Use includeKeys in StoreEvent\n\nYou can prevent unnecessary update calls with `includeKeys`.\nIn this case, events calls [areSimilar function](https://github.com/ibitcy/react-stores/blob/master/src/compare.ts) to compare previous state and next state using only the keys you provided to the `includeKeys` array.\n\n```typescript\ncomonentDidMount() {\n  // You call setState each time when storeState changes even if storeState.mapOfObjects does not exist\n  // It's not a big deal while you get only primitives from a store state, like strings or numbers\n  this.storeEvent = myStore.on(\n    StoreEventType.All,\n    (storeState) =\u003e {\n      this.setState({\n        momentousMap: storeState.mapOfObjects,\n      });\n    },\n  );\n}\n```\n\n```typescript\ncomonentDidMount() {\n  //You can prevent update call for unnecessary keys in\n  // and watch only for an important key for this component\n  this.storeEvent = myStore.on(\n    StoreEventType.All,\n    // Watch only for mapOfObjects key from the store\n    ['mapOfObjects'],\n    (storeState) =\u003e {\n      // The callback is fired only when mapOfObjects key was changed\n      this.setState({\n        momentousMap: storeState.mapOfObjects,\n      });\n    },\n  );\n}\n```\n\n### Use includeKeys in useStore\n\nYou can prevent unnecessary update calls with `includeKeys` passed to the `useStore`.\nIn this case, events calls the [areSimilar function](https://github.com/ibitcy/react-stores/blob/master/src/compare.ts) to compare previous state and next state uses only keys witch you pass into `includeKeys`.\n\n```typescript\n// You call setState each time when storeState changes even if storeState.mapOfObjects does not exist\n// It's not a big deal when you grab a primitives from store, like a strings or a numbers\nconst { mapOfObjects } = useStore(myStore, StoreEventType.Update /* Optional */);\n```\n\n```typescript\n// You can prevent update call for unnecessary keys in the store\n// and watch only for important keys for this component\nconst { mapOfObjects } = useStore(myStore, ['mapOfObjects'], StoreEventType.Update /* Optional */);\n```\n\n### Use mapState in useStore\n\nLet's look at this example. In this case, CounterComponent will re-render every time after any of the keys in myStore were changed.\nThis happens because after changing we get a new copy of the store state and forcing the update.\n\n```typescript jsx\nimport React from 'react';\nimport { useStore } from 'react-stores';\nimport { myStore } from './myStore';\n\nexport const CounterComponent = ({ value }) =\u003e {\n  // Component re-renders when myStore state changes\n  const counter = useStore(myStore);\n\n  /*\n   * This code executes when myStore state changes\n   */\n  return \u003cdiv\u003e{counter}\u003c/div\u003e;\n};\n```\n\nYou can use `mapState` function to pick primitives from state and pass them into your component.\n\n```typescript jsx\nimport React from 'react';\nimport { useStore } from 'react-stores';\nimport { myStore } from './myStore';\n\nexport const CounterComponent = ({ value }) =\u003e {\n  // Okay, now component will re-render only when the counter property actually changed\n  // mapState function returns primitive\n  const counter = useStore(myStore, state =\u003e state.counter);\n\n  return \u003cdiv\u003e{counter}\u003c/div\u003e;\n};\n```\n\nIt works because useHook uses strict `===` reference equality that checks next mapped state and previous mapped state. For primitives, it works perfectly, but let's look at this:\n\n```typescript jsx\nimport React from 'react';\nimport { useStore } from 'react-stores';\nimport { myStore } from './myStore';\n\nexport const CounterComponent = ({ value }) =\u003e {\n  // Now component re-renders every time we change store state\n  // It is also relevant when you map two or more keys\n  const { counter } = useStore(myStore, state =\u003e ({ counter: state.counter }));\n\n  /*\n   * All this code will be executed when myStore were changed\n   */\n\n  return \u003cdiv\u003e{counter}\u003c/div\u003e;\n};\n```\n\nIt happens because mapState(nextState) does not equal the previous mapState, they are different objects. You can fix it with [`compare`](#use-compare-in-usestore) function.\n\n### Use compare in useStore\n\nWhen you use `mapState` with only few keys, your component will re-render even if keys did not changed. Take a look:\n\n```typescript jsx\nimport React from 'react';\nimport { useStore } from 'react-stores';\nimport { myStore } from './myStore';\n\nexport const CounterComponent = ({ value }) =\u003e {\n  // Now component re-renders every time\n  // It is also relevant when you map two or more keys\n  const { counter } = useStore(myStore, state =\u003e ({ counter: state.counter }));\n\n  /*\n   * All this code will be executed when myStore were changed\n   */\n\n  return \u003cdiv\u003e{counter}\u003c/div\u003e;\n};\n```\n\nIt happens because mapState(nextState) not equal previous mapState, they are different objects. Let's use `compare` function to fix it.\n\n```typescript jsx\nimport React from 'react';\nimport { useStore } from 'react-stores';\n// You can use `areSimilar` function exported from react-stores\nimport { areSimilar } from 'react-stores';\nimport { myStore } from './myStore';\n\nexport const CounterComponent = ({ value }) =\u003e {\n  // Re-render component only when counter or anotherValue was changed\n  const { counter, anotherValue } = useStore(\n    myStore,\n    state =\u003e ({ counter: state.counter, anotherValue: state.anotherValue }),\n    // Use your custom compare function to prevent re-renders\n    // if the store was changed but mapped values are the same.\n    (a, b) =\u003e a.counter === b.counter \u0026\u0026 someCompareFunction(a.anotherValue, b.anotherValue),\n  );\n\n  return (\n    \u003cdiv\u003e\n      {counter}, {anotherValue.id}\n    \u003c/div\u003e\n  );\n};\n```\n\n# Debugging\n\nInstall [extension for chrome](https://github.com/ibitcy/react-stores-devtools-extension#react-stores-devtools-extension) devtools for better debugging.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fibitcy%2Freact-stores","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fibitcy%2Freact-stores","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fibitcy%2Freact-stores/lists"}