{"_id":"@risingstack/react-easy-state","_rev":"11-7f8791ca24b6c37df9c5fd1db0d2c992","name":"@risingstack/react-easy-state","dist-tags":{"alpha":"6.3.1-alpha.1","latest":"6.3.0","experimental":"0.0.0-experimental-912b2213"},"versions":{"6.1.3":{"name":"@risingstack/react-easy-state","version":"6.1.3","private":false,"description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es6.js","module":"dist/es.es6.js","types":"types/index.d.ts","scripts":{"test-native":"NATIVE=true jest --config ./jest.native.json","test-web":"jest --config ./jest.web.json","test-web-no-hook":"NOHOOK=true jest --config ./jest.no-hook.json","test":"npm run test-web && npm run test-web-no-hook && npm run test-native","example":"node ./scripts/startExample.js","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"eslint --max-warnings 0 --ext js,jsx src scripts __tests__ __mocks__","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","build":"rollup --config","build-toc":"node ./scripts/buildToc.js"},"husky":{"hooks":{"pre-commit":"npm run lint","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-push":"npm t"}},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/RisingStack/react-easy-state.git"},"bugs":{"url":"https://github.com/RisingStack/react-easy-state/issues"},"homepage":"https://github.com/RisingStack/react-easy-state#readme","license":"MIT","keywords":["observable","react-component","react","reactjs","reactive","model","frp","functional-reactive-programming","state management","es6 proxy"],"dependencies":{"@nx-js/observer-util":"^4.2.2"},"peerDependencies":{"react":"*"},"devDependencies":{"@babel/core":"^7.8.4","@babel/plugin-proposal-class-properties":"^7.8.3","@babel/plugin-proposal-export-default-from":"^7.8.3","@babel/plugin-transform-async-to-generator":"^7.8.3","@babel/plugin-transform-modules-commonjs":"^7.8.3","@babel/polyfill":"^7.8.3","@babel/preset-env":"^7.8.4","@babel/preset-react":"^7.8.3","@commitlint/cli":"^8.3.5","@commitlint/config-angular":"^8.3.4","@rollup/plugin-node-resolve":"^7.1.1","@testing-library/jest-dom":"^5.1.1","@testing-library/react":"^9.4.0","@types/react":"^16.9.19","babel-eslint":"^10.0.3","classnames":"^2.2.6","coveralls":"^3.0.9","eslint":"^6.1.0","eslint-config-airbnb":"^18.0.1","eslint-config-prettier":"^6.10.0","eslint-plugin-import":"^2.20.1","eslint-plugin-jsx-a11y":"^6.2.3","eslint-plugin-prettier":"^3.1.2","eslint-plugin-react":"^7.18.3","eslint-plugin-react-hooks":"^1.7.0","husky":"^4.2.3","jest":"^25.1.0","markdown-toc":"^1.2.0","moment":"^2.24.0","nyc":"^15.0.0","no-hook-react":"npm:react@16.7.0","no-hook-react-dom":"npm:react-dom@16.7.0","no-hook-react-testing-library":"npm:react-testing-library@5.4.4","prettier":"^1.19.1","react":"^16.12.0","react-dom":"^16.12.0","react-native":"^0.61.5","react-native-testing-library":"^1.12.0","react-router-dom":"^5.1.2","react-test-renderer":"^16.12.0","rollup":"^1.31.0","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.3","sinon":"^8.1.1","styled-components":"^5.0.1"},"engines":{"node":">=10.0.0","npm":">=6.9.0"},"gitHead":"c4112a440d5bf435735edc9ef342e9983c9395b4","_id":"@risingstack/react-easy-state@6.1.3","_nodeVersion":"12.16.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-V8d/QZr6yetd0RfxiIabGUD2QY0PAR3XQes5RW+sLNbRn6KC6RllMWni3pbnlg/98ZeKg901RB7cE/j+e9ZHJw==","shasum":"67c993a72d75fc94ade899f08fd0d806d4083e6a","tarball":"https://registry.npmjs.org/@risingstack/react-easy-state/-/react-easy-state-6.1.3.tgz","fileCount":12,"unpackedSize":157792,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeaOAxCRA9TVsSAnZWagAAvyYP/iU4Tv6ETimx5UZEjfP5\nqSNs716c1m+aq1kuKAWzKS5y/lhien8taMbNY+DExLlQEdOIzPS6JAxP5mtj\n/824HXW96Z+Qe/2xPLv8PVncX4ntOBIxtb/HxINYpwT2dq/spXCkCcPMzlyy\n749xuaTt5VZyyjYRFIc1D7vhsgI0jekvxbgPtQU3HmnhyXP0Ik2kJuuAqbPY\nF0ad2y+VeycTSASoUBk168U8obRElmPER96ZTlzCDQPNW6g1lVF+/lcOyJtp\nA6V2jUip7GOKe8gBsl87AOUIBc+l4KOvPqu1JqYYOh+ltn5DVqbJyLp7yX+J\nu+1npwzVXBF1CS9ORTiV8YsGJ+wXDDguQ19XC1tDfZsjnNJb5azPeRVNE2Gs\nzMjlQzE58HYUVwrBg8EeNAKRNLVqtDVfDjxz8/PRP/MUZCTo6CkByvQdGJqw\nDhUQJ+dNhK8OqVrvmHcUYv3ijGlFThWUi8HCiKwDTQfswT/f0tpAV0ylg/9p\n4nxZeu2dOxXPY7t/b43jy7Hvhxze/VwB/nD2FZfVFD+npjwjyOGA0j2pBeua\nxO/LZlGR6VyPIHckpDaRcZQCT19ttUYgtUcSCqT4gDFJJFY1Ojs3AIIl76oU\n5c2zXO5TCWcm/UNOL+MU414L9naP0ah0v9gNi59RI5Pse53d8V8X0ZVKlYCH\n6iF/\r\n=JgOQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDkh4sDfAmsC4ZfLn+rfqVr7ohTsU0lBzAy9XY0PZ7SgQIgY8B3/R01x1a50Z7j7MXYR2ipkJC/ibdvJ9wpqOVz1FM="}]},"maintainers":[{"name":"kubischj","email":"kubischj@windowslive.com"},{"name":"fwalkwithm","email":"fwalkwithm@gmail.com"},{"name":"ozonid","email":"david@risingstack.com"},{"name":"jota","email":"simonzsoltjota@gmail.com"},{"name":"dandesz198","email":"dandesz198@gmail.com"},{"name":"paldiana01","email":"diana.pal@risingstack.com"},{"name":"risingnpm","email":"info@risingstack.com"},{"name":"gergelyke","email":"mail@nemethgergely.com"},{"name":"hekike","email":"email@martonpeter.com"},{"name":"peteyycz","email":"p.czibik@gmail.com"},{"name":"tamas.hodi","email":"tamas.hodi89@gmail.com"},{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"}],"_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.3_1583931441161_0.7501214153582387"},"_hasShrinkwrap":false},"6.2.0":{"name":"@risingstack/react-easy-state","version":"6.2.0","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es6.js","module":"dist/es.es6.js","types":"types/index.d.ts","scripts":{"test-native":"NATIVE=true jest --config ./jest.native.json --silent","test-web":"jest --config ./jest.web.json --silent","test-web-no-hook":"NOHOOK=true jest --config ./jest.no-hook.json --silent","test":"npm run test-web && npm run test-web-no-hook && npm run test-native","example":"node ./scripts/startExample.js","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"eslint --max-warnings 0 --ext js,jsx src scripts __tests__ __mocks__","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","build":"rollup --config","build-toc":"node ./scripts/buildToc.js","semantic-release":"semantic-release","contributors":"all-contributors generate"},"husky":{"hooks":{"pre-commit":"npm run lint","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-push":"npm t"}},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+https://github.com/RisingStack/react-easy-state.git"},"bugs":{"url":"https://github.com/RisingStack/react-easy-state/issues"},"homepage":"https://github.com/RisingStack/react-easy-state#readme","license":"MIT","keywords":["observable","react-component","react","reactjs","reactive","model","frp","functional-reactive-programming","state management","es6 proxy"],"dependencies":{"@nx-js/observer-util":"^4.2.2"},"peerDependencies":{"react":"*"},"devDependencies":{"@babel/core":"^7.8.7","@babel/plugin-proposal-class-properties":"^7.8.3","@babel/plugin-proposal-export-default-from":"^7.8.3","@babel/plugin-transform-async-to-generator":"^7.8.3","@babel/plugin-transform-modules-commonjs":"^7.8.3","@babel/polyfill":"^7.8.7","@babel/preset-env":"^7.8.7","@babel/preset-react":"^7.8.3","@commitlint/cli":"^8.3.5","@commitlint/config-angular":"^8.3.4","@rollup/plugin-node-resolve":"^7.1.1","@testing-library/jest-dom":"^5.1.1","@testing-library/react":"^10.0.1","@types/react":"^16.9.23","all-contributors-cli":"^6.14.0","babel-eslint":"^10.1.0","classnames":"^2.2.6","coveralls":"^3.0.9","eslint":"^6.8.0","eslint-config-airbnb":"^18.1.0","eslint-config-prettier":"^6.10.0","eslint-plugin-import":"^2.20.1","eslint-plugin-jsx-a11y":"^6.2.3","eslint-plugin-prettier":"^3.1.2","eslint-plugin-react":"^7.19.0","eslint-plugin-react-hooks":"^2.5.0","husky":"^4.2.3","jest":"^25.1.0","markdown-toc":"^1.2.0","moment":"^2.24.0","no-hook-react":"npm:react@16.7.0","no-hook-react-dom":"npm:react-dom@16.7.0","no-hook-react-testing-library":"npm:react-testing-library@5.4.4","nyc":"^15.0.0","prettier":"^1.19.1","react":"^16.12.0","react-dom":"^16.13.0","react-native":"^0.61.5","react-native-testing-library":"^1.12.0","react-router-dom":"^5.1.2","react-test-renderer":"^16.13.0","rollup":"^2.0.6","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.4.0","semantic-release":"^17.0.4","sinon":"^9.0.1","styled-components":"^5.0.1"},"engines":{"node":">=10.0.0","npm":">=6.9.0"},"gitHead":"be44bbdeb52c6025e81c99528ed7b0d932c5be18","_id":"@risingstack/react-easy-state@6.2.0","_nodeVersion":"10.19.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-LCLd+1LPpYIie4ivZIoPIDotb0hUVYLroS7bUcyaUihTbgAGs8vc/4qaXSb51JnM0D2ugr9Cfe5+vq8TXnUf3w==","shasum":"afdda8c26b1672cb87b7f17ba3fc67165e3a2735","tarball":"https://registry.npmjs.org/@risingstack/react-easy-state/-/react-easy-state-6.2.0.tgz","fileCount":12,"unpackedSize":181585,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJegcXuCRA9TVsSAnZWagAAnf4P/3DZqakLHU4kUD5Pi14K\nWKs+WRQtFNXJR19eek4xuJcJD8TmEE/ZYGuDecK7/DAN90n3zH6Xt5rXP0lq\nY/a70r6YlRle1SSdO6lpFw2bOuLjK/7YAZsx1W6dBIjXsys+SwetWD0xCJFC\nsvfYjJeybWA+Sx4V2POkoqYossPrPADA5sXI1o742ey8jUZPlp4k8u+rmyRb\nP/5IF9YU/tPWK9GwQM9J67llwpX9OV5ODzlNQZahS+oa3gvwobVyfDmqmxY5\nAuLV/AlrbXHX1Xk359zn/IfYV3OU6kDULl/dMVnCfFueLIbbisCWyj1IAlIF\njuTZfRETClwTMw7B+SUWRnA8JqiHJr1N47FKXtz2ZGKRV5bT7ZWLxwlgFVbh\niWwdeuu0SdPbSL7Hv36d0ugk+9i0wL7EboW0M96pziv3l8fhGXOD499A6r52\nXcxau1awiBMN1URDQwXbpuuGbcj80tboyU2lNwhfI6eKfKaekh3LSJ1jylLk\nirsflyVe2YUAC6++qrLWFOdCj/hFzIlulfCxlZRyRo+ZsWluss7+OrHsxfU9\nD4uz6BTwCC8/pRGqKS+AyvLEuqBywun7NpUz556+FBkK23lqVxoQM82sOvA6\n7nxSxe2A7TLXufCRy644HOhoDR7lQXbgLf+ix/4bNIlo0rMAdydulsAeKXYx\nO/Sl\r\n=HjCg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC7rd6GO5BvGva80x4kMzWPoq2radwFMQ5/kl70PT3RtQIgTaukvogQMV8GDY+Kyd0WMvwZZVKE+Z2NNMnAdUYF8WU="}]},"maintainers":[{"name":"dandesz198","email":"dandesz198@gmail.com"},{"name":"fwalkwithm","email":"fwalkwithm@gmail.com"},{"name":"gergelyke","email":"mail@nemethgergely.com"},{"name":"hekike","email":"email@martonpeter.com"},{"name":"jota","email":"simonzsoltjota@gmail.com"},{"name":"kubischj","email":"kubischj@windowslive.com"},{"name":"ozonid","email":"david@risingstack.com"},{"name":"paldiana01","email":"diana.pal@risingstack.com"},{"name":"peteyycz","email":"p.czibik@gmail.com"},{"name":"risingnpm","email":"info@risingstack.com"},{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},{"name":"tamas.hodi","email":"tamas.hodi89@gmail.com"}],"_npmUser":{"name":"fwalkwithm","email":"fwalkwithm@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.2.0_1585563118110_0.6130555214550626"},"_hasShrinkwrap":false},"0.0.0-experimental-912b2213":{"name":"@risingstack/react-easy-state","version":"0.0.0-experimental-912b2213","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es6.js","module":"dist/es.es6.js","types":"types/index.d.ts","scripts":{"test-native":"NATIVE=true jest --config ./jest.native.json --silent","test-web":"jest --config ./jest.web.json","test-web-no-hook":"NOHOOK=true jest --config ./jest.no-hook.json --silent","test":"npm run test-web && npm run test-web-no-hook && npm run test-native","example":"node ./scripts/startExample.js","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"eslint --max-warnings 0 --ext js,jsx src scripts __tests__ __mocks__","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","build":"rollup --config","build-toc":"node ./scripts/buildToc.js","semantic-release":"semantic-release","contributors":"all-contributors generate"},"husky":{"hooks":{"pre-commit":"npm run lint","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-push":"npm t"}},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+https://github.com/RisingStack/react-easy-state.git"},"bugs":{"url":"https://github.com/RisingStack/react-easy-state/issues"},"homepage":"https://github.com/RisingStack/react-easy-state#readme","license":"MIT","keywords":["observable","react-component","react","reactjs","reactive","model","frp","functional-reactive-programming","state management","es6 proxy"],"dependencies":{"@nx-js/observer-util":"^4.2.2"},"peerDependencies":{"react":"*"},"devDependencies":{"@babel/core":"^7.8.7","@babel/plugin-proposal-class-properties":"^7.8.3","@babel/plugin-proposal-export-default-from":"^7.8.3","@babel/plugin-transform-async-to-generator":"^7.8.3","@babel/plugin-transform-modules-commonjs":"^7.8.3","@babel/polyfill":"^7.8.7","@babel/preset-env":"^7.8.7","@babel/preset-react":"^7.8.3","@commitlint/cli":"^8.3.5","@commitlint/config-angular":"^8.3.4","@rollup/plugin-node-resolve":"^7.1.1","@testing-library/jest-dom":"^5.1.1","@testing-library/react":"^10.0.1","@types/react":"^16.9.23","all-contributors-cli":"^6.14.0","babel-eslint":"^10.1.0","classnames":"^2.2.6","coveralls":"^3.0.9","eslint":"^6.8.0","eslint-config-airbnb":"^18.1.0","eslint-config-prettier":"^6.10.0","eslint-plugin-import":"^2.20.1","eslint-plugin-jsx-a11y":"^6.2.3","eslint-plugin-prettier":"^3.1.2","eslint-plugin-react":"^7.19.0","eslint-plugin-react-hooks":"^2.5.0","husky":"^4.2.3","jest":"^25.1.0","markdown-toc":"^1.2.0","moment":"^2.24.0","no-hook-react":"npm:react@16.7.0","no-hook-react-dom":"npm:react-dom@16.7.0","no-hook-react-testing-library":"npm:react-testing-library@5.4.4","nyc":"^15.0.0","prettier":"^1.19.1","react":"^16.12.0","react-dom":"^16.13.0","react-native":"^0.61.5","react-native-testing-library":"^1.12.0","react-router-dom":"^5.1.2","react-test-renderer":"^16.13.0","rollup":"^2.0.6","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.4.0","semantic-release":"^17.0.4","sinon":"^9.0.1","styled-components":"^5.0.1"},"engines":{"node":">=10.0.0","npm":">=6.9.0"},"readme":"<p align=\"center\">\n  <img src=\"images/logo.svg\" width=\"600px\" height=\"auto\" />\n</p>\n\n## React Easy State - by [RisingStack](https://risingstack.com/)\n\n[![Build](https://img.shields.io/circleci/project/github/RisingStack/react-easy-state/master.svg)](https://circleci.com/gh/RisingStack/react-easy-state/tree/master) [![dependencies Status](https://david-dm.org/RisingStack/react-easy-state/status.svg)](https://david-dm.org/RisingStack/react-easy-state) [![Coverage Status](https://coveralls.io/repos/github/RisingStack/react-easy-state/badge.svg?branch=master&service=github)](https://coveralls.io/github/RisingStack/react-easy-state?branch=master) [![Package size](https://img.shields.io/bundlephobia/minzip/@risingstack/react-easy-state.svg)](https://bundlephobia.com/result?p=@risingstack/react-easy-state) [![Version](https://img.shields.io/npm/v/@risingstack/react-easy-state.svg)](https://www.npmjs.com/package/@risingstack/react-easy-state) [![License](https://img.shields.io/npm/l/@risingstack/react-easy-state.svg)](https://www.npmjs.com/package/@risingstack/react-easy-state) <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->\n[![All Contributors](https://img.shields.io/badge/all_contributors-4-blue.svg)](#contributors)\n<!-- ALL-CONTRIBUTORS-BADGE:END -->\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" height=\"auto\" /></a>\n\n**NEWS:** `react-easy-state` is moved under `@risingstack/react-easy-state` on npm with **no breaking changes**. Please switch to the new package to get the latest features and bug fixes. Thanks!\n\n<details>\n<summary><strong>Table of Contents</strong></summary>\n<!-- Do not edit the Table of Contents, instead regenerate with `npm run build-toc` -->\n\n<!-- toc -->\n\n* [Introduction :wave:](#introduction-wave)\n* [Installation :cd:](#installation-cd)\n* [Everyday Usage :sunglasses:](#everyday-usage-sunglasses)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Advanced Usage :nerd_face:](#advanced-usage-nerd_face)\n  + [Adding side effects](#adding-side-effects)\n* [API Summary :book:](#api-summary-book)\n  + [store(obj)](#storeobj)\n  + [view(Comp)](#viewcomp)\n  + [batch(fn)](#batchfn)\n  + [autoEffect(fn)](#autoeffectfn)\n  + [clearEffect(fn)](#cleareffectfn)\n* [Examples with live demos :tv:](#examples-with-live-demos-tv)\n* [Articles :loudspeaker:](#articles-loudspeaker)\n* [Performance :rocket:](#performance-rocket)\n* [Platform support :computer:](#platform-support-computer)\n* [Alternative builds :wrench:](#alternative-builds-wrench)\n* [Contributors :sparkles:](#contributors-sparkles)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction :wave:\n\nReact Easy State is a practical state management library with two functions and two accompanying rules.\n\n1.  Always wrap your components with `view()`.\n2.  Always wrap your state store objects with `store()`.\n\n```jsx\nimport React from 'react';\nimport { store, view } from '@risingstack/react-easy-state';\n\nconst counter = store({\n  num: 0,\n  increment: () => counter.num++\n});\n\nexport default view(() => (\n  <button onClick={counter.increment}>{counter.num}</button>\n));\n```\n\nThis is enough for it to automatically update your views when needed. It doesn't matter how you structure or mutate your state stores, any syntactically valid code works.\n\nCheck this [TodoMVC codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/todo-mvc?module=%2Fsrc%2FtodosStore.js) or [raw code](/examples/todo-mvc/src/todosStore.js) for a more exciting example with nested data, arrays and computed values.\n\n## Installation :cd:\n\n`npm install @risingstack/react-easy-state`\n\n<details>\n<summary><strong>Setting up a quick project</strong></summary>\n<p></p>\n\nEasy State supports <a href=\"https://github.com/facebookincubator/create-react-app\">Create React App</a> without additional configuration. Just run the following commands to get started.\n\n```sh\nnpx create-react-app my-app\ncd my-app\nnpm install @risingstack/react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Everyday Usage :sunglasses:\n\n### Creating global stores\n\n`store` creates a state store from the passed object and returns it. A state store behaves just like the passed object. (To be precise, it is a transparent reactive proxy of the original object.)\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Rick' });\n// stores behave like normal JS objects\nuser.name = 'Bob';\n```\n\n<details>\n<summary>State stores may have arbitrary structure and they may be mutated in any syntactically valid way.</summary>\n<p></p>\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\n// stores can include any valid JS structure\n// including nested data, arrays, Maps, Sets, getters, setters, inheritance, ...\nconst user = store({\n  profile: {\n    firstName: 'Bob',\n    lastName: 'Smith',\n    get name() {\n      return `${user.firstName} ${user.lastName}`;\n    },\n  },\n  hobbies: ['programming', 'sports'],\n  friends: new Map(),\n});\n\n// stores may be mutated in any syntactically valid way\nuser.profile.firstName = 'Bob';\ndelete user.profile.lastName;\nuser.hobbies.push('reading');\nuser.friends.set('id', otherUser);\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Async operations can be expressed with the standard async/await syntax.</summary>\n<p></p>\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst userStore = store({\n  user: {},\n  async fetchUser() {\n    userStore.user = await fetch('/user');\n  },\n});\n\nexport default userStore;\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>State stores may import and use other state stores in their methods.</summary>\n<p></p>\n\n_userStore.js_\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst userStore = store({\n  user: {},\n  async fetchUser() {\n    userStore.user = await fetch('/user');\n  },\n});\n\nexport default userStore;\n```\n\n_recipesStore.js_\n\n```js\nimport { store } from '@risingstack/react-easy-state';\nimport userStore from './userStore';\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(\n      `/recipes?user=${userStore.user.id}`,\n    );\n  },\n});\n\nexport default recipesStore;\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Wrap your state stores with <code>store</code> as early as possible.</summary>\n<p></p>\n\n```js\n// DON'T DO THIS\nconst person = { name: 'Bob' };\nperson.name = 'Ann';\n\nexport default store(person);\n```\n\n```js\n// DO THIS INSTEAD\nconst person = store({ name: 'Bob' });\nperson.name = 'Ann';\n\nexport default person;\n```\n\nThe first example wouldn't trigger re-renders on the `person.name = 'Ann'` mutation, because it is targeted at the raw object. Mutating the raw - none `store`-wrapped object - won't schedule renders.\n\n</details>\n<p></p>\n\n<details>\n<summary>Avoid using the <code>this</code> keyword in the methods of your state stores.</summary>\n<p></p>\n\n```jsx\nimport { store, view } from '@risingstack/react-easy-state';\n\nconst counter = store({\n  num: 0,\n  increment() {\n    // DON'T DO THIS\n    this.num++;\n    // DO THIS INSTEAD\n    counter.num++;\n  },\n});\n\nexport default view(() => (\n  <div onClick={counter.increment}>{counter.num}</div>\n));\n```\n\n`this.num++` won't work, because `increment` is passed as a callback and loses its `this`. You should use the direct object reference - `counter` - instead of `this`.\n\n</details>\n\n### Creating reactive views\n\nWrapping your components with `view` turns them into reactive views. A reactive view re-renders whenever a piece of store - used inside its render - changes.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\n// this is a global state store\nconst user = store({ name: 'Bob' });\n\n// this is re-rendered whenever user.name changes\nexport default view(() => (\n  <div>\n    <input\n      value={user.name}\n      onChange={ev => (user.name = ev.target.value)}\n    />\n    <div>Hello {user.name}!</div>\n  </div>\n));\n```\n\n<details>\n<summary><strong>Wrap ALL of your components with <code>view</code> - including class and function ones - even if they don't seem to directly use a store.</strong></summary>\n<p></p>\n\n```jsx\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst appStore = store({\n  user: { name: 'Ann' },\n});\n\nconst App = view(() => (\n  <div>\n    <h1>My App</h1>\n    <Profile user={appStore.user} />\n  </div>\n));\n\n// DO THIS\nconst Profile = view(({ user }) => <p>Name: {user.name}</p>);\n\n// DON'T DO THIS\n// This won't re-render on appStore.user.name = 'newName' like mutations\nconst Profile = ({ user }) => <p>Name: {user.name}</p>;\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>A single reactive component may use multiple stores inside its render.</summary>\n<p></p>\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' });\nconst timeline = store({ posts: ['react-easy-state'] });\n\n// this is re-rendered whenever user.name or timeline.posts[0] changes\nexport default view(() => (\n  <div>\n    <div>Hello {user.name}!</div>\n    <div>Your first post is: {timeline.posts[0]}</div>\n  </div>\n));\n```\n\n</details>\n<p></p>\n\n<details>\n<summary><code>view</code> implements an optimal <code>shouldComponentUpdate</code> (or <code>memo</code>) for your components.</summary>\n<p></p>\n\n- Using `PureComponent` or `memo` will provide no additional performance benefits.\n\n- Defining a custom `shouldComponentUpdate` may rarely provide performance benefits when you apply some use case specific heuristics inside it.\n\n</details>\n<p></p>\n\n<details>\n<summary>Reactive renders are batched. Multiple synchronous store mutations won't result in multiple re-renders of the same component.</summary>\n<p></p>\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob', age: 30 });\n\nfunction mutateUser() {\n  user.name = 'Ann';\n  user.age = 32;\n}\n\n// calling `mutateUser` will only trigger a single re-render of the below component\n// even though it mutates the store two times in quick succession\nexport default view(() => (\n  <div onClick={mutateUser}>\n    name: {user.name}, age: {user.age}\n  </div>\n));\n```\n\nIf you mutate your stores multiple times synchronously from **exotic task sources**, multiple renders may rarely happen. If you experience performance issues you can batch changes manually with the `batch` function. `batch(fn)` executes the passed function immediately and batches any subsequent re-renders until the function execution finishes.\n\n```jsx\nimport React from 'react';\nimport { view, store, batch } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob', age: 30 });\n\nfunction mutateUser() {\n  // this makes sure the state changes will cause maximum one re-render,\n  // no matter where this function is getting invoked from\n  batch(() => {\n    user.name = 'Ann';\n    user.age = 32;\n  });\n}\n\nexport default view(() => (\n  <div>\n    name: {user.name}, age: {user.age}\n  </div>\n));\n```\n\n> **NOTE:** The React team plans to improve render batching in the future. The `batch` function and built-in batching may be deprecated and removed in the future in favor of React's own batching.\n\n</details>\n<p></p>\n\n<details>\n<summary>Always apply <code>view</code> as the latest (innermost) wrapper when you combine it with other Higher Order Components.</summary>\n<p></p>\n\n```jsx\nimport { view } from '@risingstack/react-easy-state';\nimport { withRouter } from 'react-router-dom';\nimport { withTheme } from 'styled-components';\n\nconst Comp = () => <div>A reactive component</div>;\n\n// DO THIS\nwithRouter(view(Comp));\nwithTheme(view(Comp));\n\n// DON'T DO THIS\nview(withRouter(Comp));\nview(withTheme(Comp));\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Usage with (pre v4.4) React Router.</summary>\n<p></p>\n\n- If routing is not updated properly, wrap your `view(Comp)` - with the `Route`s inside - in `withRouter(view(Comp))`. This lets react-router know when to update.\n\n- The order of the HOCs matter, always use `withRouter(view(Comp))`.\n\nThis is not necessary if you use React Router 4.4+. You can find more details and some reasoning about this in [this react-router docs page](https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md).\n\n</details>\n<p></p>\n\n<details>\n<summary>Usage with React Developer Tools.</summary>\n<p></p>\n\nIf you want React Developer Tools to recognize your reactive view components' names, you have to pass either a **named function** or an anonymous function with **name inference** to the `view` wrapper.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({\n  name: 'Rick',\n});\n\nconst componentName = () => (\n  <div>{user.name}</div>\n);\n\nexport default view(componentName);\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Passing nested data to third party components.</summary>\n<p></p>\n\nThird party helpers - like data grids - may consist of many internal components which can not be wrapped by `view`, but sometimes you would like them to re-render when the passed data mutates. Traditional React components re-render when their props change by reference, so mutating the passed reactive data won't work in these cases. You can solve this issue by deep cloning the observable data before passing it to the component. This creates a new reference for the consuming component on every store mutation.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\nimport Table from 'rc-table';\nimport cloneDeep from 'lodash/cloneDeep';\n\nconst dataStore = store({\n  items: [\n    {\n      product: 'Car',\n      value: 12,\n    },\n  ],\n});\n\nexport default view(() => (\n  <Table data={cloneDeep(dataStore.items)} />\n));\n```\n\n</details>\n\n### Creating local stores\n\nA singleton global store is perfect for something like the current user, but sometimes having local component states is a better fit. Just create a store inside a function component or as a class component property in these cases.\n\n#### Local stores in function components\n\n```jsx\nimport React from 'react'\nimport { view, store } from '@risingstack/react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  const increment = () => counter.num++\n  return <button={increment}>{counter.num}</div>\n})\n```\n\n**Local stores in functions rely on React hooks. They require React and React DOM v16.8+ or React Native v0.59+ to work.**\n\n<details>\n<summary>You can use React hooks - including <code>useState</code> - in function components, Easy State won't interfere with them. Consider using <a href=\"#local-auto-effects-in-function-components\">autoEffect</a> instead of the <code>useEffect</code> hook for the best experience though.</summary>\n<p></p>\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nexport default view(() => {\n  const [name, setName] = useState('Ann');\n  const user = store({ age: 30 });\n  return (\n    <div>\n      <input value={name} onChange={ev => setName(ev.target.value)} />\n      <input\n        value={user.age}\n        onChange={ev => (user.age = ev.target.value)}\n      />\n    </div>\n  );\n});\n```\n\n</details>\n\n#### Local stores in class components\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass Counter extends Component {\n  counter = store({ num: 0 });\n  increment = () => counter.num++;\n\n  render() {\n    return (\n      <button onClick={this.increment}>{this.counter.num}</button>\n    );\n  }\n}\n\nexport default view(Counter);\n```\n\n<details>\n<summary>You can also use vanilla <code>setState</code> in your class components, Easy State won't interfere with it.</summary>\n<p></p>\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass Profile extends Component {\n  state = { name: 'Ann' };\n  user = store({ age: 30 });\n\n  setName = ev => this.setState({ name: ev.target.value });\n  setAge = ev => (this.user.age = ev.target.value);\n\n  render() {\n    return (\n      <div>\n        <input value={this.state.name} onChange={this.setName} />\n        <input value={this.user.age} onChange={this.setAge} />\n      </div>\n    );\n  }\n}\n\nexport default view(Profile);\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Don't name local stores as <code>state</code>. It may conflict with linter rules, which guard against direct state mutations.</summary>\n<p></p>\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass Profile extends Component {\n  // DON'T DO THIS\n  state = store({});\n  // DO THIS\n  user = store({});\n  render() {}\n}\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Deriving local stores from props (<code>getDerivedStateFromProps</code>).</summary>\n<p></p>\n\nClass components wrapped with `view` have an extra static `deriveStoresFromProps` lifecycle method, which works similarly to the vanilla `getDerivedStateFromProps`.\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass NameCard extends Component {\n  userStore = store({ name: 'Bob' });\n\n  static deriveStoresFromProps(props, userStore) {\n    userStore.name = props.name || userStore.name;\n  }\n\n  render() {\n    return <div>{this.userStore.name}</div>;\n  }\n}\n\nexport default view(NameCard);\n```\n\nInstead of returning an object, you should directly mutate the received stores. If you have multiple local stores on a single component, they are all passed as arguments - in their definition order - after the first props argument.\n\n</details>\n\n## Advanced Usage :nerd_face:\n\n### Adding side effects\n\nUse `autoEffect` to react with automatic side effect to your store changes. Auto effects should contain end-of-chain logic - like changing the document title or saving data to LocalStorage. `view` is a special auto effect that does rendering.\n\n<details>\n<summary>Never use auto effects to derive data from other data. Use dynamic getters instead.</summary>\n<p></p>\n\n```jsx\nimport { store, autoEffect } from '@risingstack/react-easy-state';\n\n// DON'T DO THIS\nconst store1 = store({ name: 'Store 1' })\nconst store2 = store({ name: 'Store 2' })\nautoEffect(() => store2.name = store1.name)\n\n// DO THIS INSTEAD\nconst store1 = store({ name: 'Store 1' })\nconst store2 = store({ get name () { return store1.name } })\n```\n\n</details>\n<p></p>\n\n#### Global auto effects\n\nGlobal auto effects can be created with `autoEffect` and cleared up with `clearEffect`.\n\n```jsx\nimport { store, autoEffect, clearEffect } from '@risingstack/react-easy-state';\n\nconst app = store({ name: 'My App' })\nconst effect = autoEffect(() => document.title = app.name)\n\n// this also updates the document title\napp.name = 'My Awesome App'\n\nclearEffect(effect)\n// this won't update the document title, the effect is cleared\napp.name = 'My App'\n```\n\n#### Local auto effects in function components\n\nUse local auto effects in function components instead of the `useEffect` hook when reactive stores are used inside them. These local effects are automatically cleared when the component unmounts.\n\n```jsx\nimport React from 'react'\nimport { store, view, autoEffect } from '@risingstack/react-easy-state';\n\nexport default view(() => {\n  const app = store({ name: 'My App' })\n  // no need to clear the effect\n  autoEffect(() => document.title = app.name)\n})\n```\n\n<details>\n<summary>Explicitly pass none reactive dependencies - like vanillas props and state - to local auto effects in function components.</summary>\n<p></p>\n\nBecause of the design of React hooks you have to explicitly pass all none reactive data to a hook-like dependency array. This makes sure that the effect also runs when the none reactive data changes.\n\n```jsx\nimport React from 'react'\nimport { store, view, autoEffect } from '@risingstack/react-easy-state';\n\nexport default view(({ greeting }) => {\n  const app = store({ name: 'My App' })\n  // pass `greeting` in the dependency array because it is not coming from a store\n  autoEffect(() => document.title = `${greeting} ${app.name}`, [greeting])\n})\n```\n\n</details>\n<p></p>\n\n#### Local auto effects in class components\n\nLocal effects in class components must be cleared when the component unmounts.\n\n```jsx\nimport React, { Component } from 'react'\nimport { store, view, autoEffect } from '@risingstack/react-easy-state';\n\nclass App extends Component {\n  app = store({ name: 'My App' })\n\n  componentDidMount () {\n    this.effect = autoEffect(() => document.title = this.app.name)\n  }\n\n  componentWillUnmount () {\n    // local effects in class components must be cleared on unmount\n    clearEffect(this.effect)\n  }\n}\n```\n\n## API Summary :book:\n\n### store(obj)\n\nCreates an observable store from the passed object and returns it. Can be used outside components for [global stores](#creating-global-stores) and inside components for [local stores]((#creating-local-stores)).\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Rick' });\n```\n\n### view(Comp)\n\nCreates a [reactive view](#creating-reactive-views) from the passed component and returns it. A reactive view re-renders whenever any store data used inside it is mutated.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' });\n\nexport default view(() => (\n  <div>Hello {user.name}!</div>\n));\n```\n\n### batch(fn)\n\nImmediately executes the passed function and batches all store mutations inside it. Batched mutations are guaranteed to not trigger unnecessary double renders. Most task sources are batched automatically, only  use `batch` if you encounter performance issues.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' });\n\nfunction setName() {\n  batch(() => {\n    user.name = 'Rick'\n    user.name = 'Ann'\n  })\n}\n```\n\n### autoEffect(fn)\n\nCreates a reactive function from the passed one, immediately executes it, and returns it. A reactive function automatically re-reruns whenever any store data used inside it is mutated.\n\nCan be used both [outside](#global-auto-effects) and [inside](#local-auto-effects-in-function-components) components.\n\n```js\nimport { store, autoEffect } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' })\n\nautoEffect(() => document.title = user.name)\n```\n\n### clearEffect(fn)\n\nTakes a reactive function (returned by `autoEffect`) and clears the reactivity from it. Cleared reactive functions will no longer re-rerun on related store mutations. Reactive functions created inside function components are automatically cleared when the component unmounts.\n\n```js\nimport { store, autoEffect, clearEffect } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' })\n\nconst effect = autoEffect(() => document.title = user.name)\nclearEffect(effect)\n```\n\n## Examples with live demos :tv:\n\n#### Beginner\n\n- [Clock Widget](https://risingstack.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/clock)) ([react-native source](/examples/native-clock/)) ([react-native sandbox](https://snack.expo.io/@git/github.com/RisingStack/react-easy-state:examples/native-clock)): a reusable clock widget with a tiny local state store.\n- [Stopwatch](https://risingstack.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/stop-watch)) ([tutorial](https://hackernoon.com/introducing-react-easy-state-1210a156fa16)): a stopwatch with a mix of normal and computed state properties.\n\n#### Advanced\n\n- [Pokédex](https://risingstack.github.io/react-easy-state/examples/pokedex/build) ([source](/examples/pokedex/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/pokedex)): a Pokédex app build with Apollo GraphQL, async actions and a global state.\n- [TodoMVC](https://risingstack.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/todo-mvc)): a classic TodoMVC implementation with a lot of computed data and implicit reactivity.\n- [Contacts Table](https://risingstack.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n- [Beer Finder](https://risingstack.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/beer-finder)) ([tutorial](https://medium.com/@solkimicreb/design-patterns-with-react-easy-state-830b927acc7c)): an app with async actions and a mix of local and global state, which finds matching beers for your meal.\n\n## Articles :loudspeaker:\n\n- [Introducing React Easy State](https://blog.risingstack.com/introducing-react-easy-state/): making a simple stopwatch.\n- [Stress Testing React Easy State](https://medium.com/@solkimicreb/stress-testing-react-easy-state-ac321fa3becf): demonstrating Easy State's reactivity with increasingly exotic state mutations.\n- [Design Patterns with React Easy State](https://medium.com/@solkimicreb/design-patterns-with-react-easy-state-830b927acc7c): demonstrating async actions and local and global state management through a beer finder app.\n- [The Ideas Behind React Easy State](https://medium.com/dailyjs/the-ideas-behind-react-easy-state-901d70e4d03e): a deep dive under the hood of Easy State.\n\n## Performance :rocket:\n\nYou can compare Easy State with plain React and other state management libraries with the below benchmarks. It performs a bit better than MobX and similarly to Redux.\n\n- [js-framework-benchmark](https://github.com/krausest/js-framework-benchmark) ([source](https://github.com/krausest/js-framework-benchmark/tree/master/react-v16.1.0-easy-state-v4.0.1-keyed)) ([results](https://rawgit.com/krausest/js-framework-benchmark/master/webdriver-ts-results/table.html))\n\n## Platform support :computer:\n\n- Node: 6 and above\n- Chrome: 49 and above\n- Firefox: 38 and above\n- Safari: 10 and above\n- Edge: 12 and above\n- Opera: 36 and above\n- React Native: 0.59 and above\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n## Alternative builds :wrench:\n\nThis library detects if you use ES6 or commonJS modules and serve the right format to you. The default bundles use ES6 features, which may not yet be supported by some minifier tools. If you experience issues during the build process, you can switch to one of the ES5 builds from below.\n\n- `@risingstack/react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n- `@risingstack/react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n- `@risingstack/react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n- `@risingstack/react-easy-state/dist/cjs.es5.js` exposes an ES5 build with commonJS modules.\n\nIf you use a bundler, set up an alias for `@risingstack/react-easy-state` to point to your desired build. You can learn how to do it with webpack [here](https://webpack.js.org/configuration/resolve/#resolve-alias) and with rollup [here](https://github.com/rollup/rollup-plugin-alias#usage).\n\n## Contributors :sparkles:\n\nContributions are always welcome, please read our [contributing documentation](CONTRIBUTING.md).\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tr>\n    <td align=\"center\"><a href=\"https://bertalan-miklos.now.sh/\"><img src=\"https://avatars3.githubusercontent.com/u/6956014?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Miklos Bertalan</b></sub></a><br /><a href=\"https://github.com/RisingStack/react-easy-state/commits?author=solkimicreb\" title=\"Code\">💻</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=solkimicreb\" title=\"Tests\">⚠️</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=solkimicreb\" title=\"Documentation\">📖</a> <a href=\"#blog-solkimicreb\" title=\"Blogposts\">📝</a></td>\n    <td align=\"center\"><a href=\"https://github.com/rolandszoke\"><img src=\"https://avatars3.githubusercontent.com/u/14181908?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Roland</b></sub></a><br /><a href=\"https://github.com/RisingStack/react-easy-state/commits?author=rolandszoke\" title=\"Code\">💻</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=rolandszoke\" title=\"Tests\">⚠️</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=rolandszoke\" title=\"Documentation\">📖</a></td>\n    <td align=\"center\"><a href=\"https://github.com/danielgrgly\"><img src=\"https://avatars3.githubusercontent.com/u/22714514?s=460&u=cbbc2326d5f671693a1f33671d9eadad902d5191&v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Daniel Gergely</b></sub></a><br /><a href=\"https://github.com/RisingStack/react-easy-state/commits?author=danielgrgly\" title=\"Code\">💻</a> <a href=\"#design-danielgrgly\" title=\"Design\">🎨</a> <a href=\"#example-danielgrgly\" title=\"Examples\">💡</a></td>\n    <td align=\"center\"><a href=\"https://github.com/peteyycz\"><img src=\"https://avatars1.githubusercontent.com/u/7130689?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Peter Czibik</b></sub></a><br /><a href=\"#infra-peteyycz\" title=\"Infrastructure (Hosting, Build-Tools, etc)\">🚇</a></td>\n  </tr>\n</table>\n\n<!-- markdownlint-enable -->\n<!-- prettier-ignore-end -->\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n","readmeFilename":"README.md","gitHead":"e23379e9e112dbd4578436a106892b3f912b2213","_id":"@risingstack/react-easy-state@0.0.0-experimental-912b2213","_nodeVersion":"12.16.1","_npmVersion":"6.13.4","dist":{"integrity":"sha512-rJF5IUSn4YksmSBe35QdKgUitSyLhVXnQAMJMmtMwGcH6DoVNWEdJi26w5CUWihKIdB+jV9rJatBwjWMWfwzjw==","shasum":"b7ef7c7a5962fc2a31f49d72a6b6917e0d45371e","tarball":"https://registry.npmjs.org/@risingstack/react-easy-state/-/react-easy-state-0.0.0-experimental-912b2213.tgz","fileCount":12,"unpackedSize":202280,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJegwYXCRA9TVsSAnZWagAAkDsP/Ri8mLq8OBCQ0EoVty/Z\nh+icKUnvbMh+3IYW9fdompfpfXmGeQ2i1yMc3LSbmJMH/TKALN0ZsQDFo1Du\ngMiBUxroS9WUdNCD4geljS2imVoCsFLBrxT2yys6KX18A4f7FKeK8k9q3mld\nvVgYzAoM20U+WcW/fzulgGUpRu1RDWZwrI+hID0q5Cns5N/rhUtdrKK+iG3v\nY0R41xezPgKnaH7hDlWtCGltKRYIrEpCeDYpgvNeYN0pjJSCkV0yihXBsjrr\n1gt/iSf9Qiz8LXrLHgQkwoHr+0w6D1K8suQwI61M5vxZkSZjWWXLyJ/CJclX\n/VP/3Ipz38z4u3zV64ryX/Do/pYlIoWun5ipDWjpWDRuADr6+thIynTtOeUb\ngUwe2kRFDhQ4Ev01hQ5QO/K/4voERdWT5gzUo8XQSxtUq2KxfNKjzJWcrYVa\nPV4/ivEuXjqz54wYFfhQSNkNfa7aIDs17DjLMJxYjKNYrCfzHgzhPwKEqMrJ\n907ZBZSTstC9vFfcO1JClYX91mcMhbLvkF8QDUOvdOJuiXPzvrCgGe/yr/DZ\nq+y4yZ2dapeK5X08bOhhqCrHs0yo0dblTgV1rBP8PHoGKbchDlalQNtu3vLt\nXOivS3f+hiI1Yd6Gil40YdIDiSN+/nVmy0olNJgHPpGoPJk1d2+qq+EVTC0f\nOvU5\r\n=05eP\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD2ExoOkVwkpdCR60YRfOCudN96iNIVSdr7IrmbpYGOtwIgSQiHqJnwlY7A0ib9Q4fXYvZAdUMXON5RAmDyBRoyJqs="}]},"maintainers":[{"name":"dandesz198","email":"dandesz198@gmail.com"},{"name":"fwalkwithm","email":"fwalkwithm@gmail.com"},{"name":"gergelyke","email":"mail@nemethgergely.com"},{"name":"hekike","email":"email@martonpeter.com"},{"name":"jota","email":"simonzsoltjota@gmail.com"},{"name":"kubischj","email":"kubischj@windowslive.com"},{"name":"ozonid","email":"david@risingstack.com"},{"name":"paldiana01","email":"diana.pal@risingstack.com"},{"name":"peteyycz","email":"p.czibik@gmail.com"},{"name":"risingnpm","email":"info@risingstack.com"},{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},{"name":"tamas.hodi","email":"tamas.hodi89@gmail.com"}],"_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_0.0.0-experimental-912b2213_1585645079091_0.06890396826164213"},"_hasShrinkwrap":false},"6.2.1":{"name":"@risingstack/react-easy-state","version":"6.2.1","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es6.js","module":"dist/es.es6.js","types":"types/index.d.ts","scripts":{"test-native":"NATIVE=true jest --config ./jest.native.json --silent","test-web":"jest --config ./jest.web.json --silent","test-web-no-hook":"NOHOOK=true jest --config ./jest.no-hook.json --silent","test":"npm run test-web && npm run test-web-no-hook && npm run test-native","example":"node ./scripts/startExample.js","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"eslint --max-warnings 0 --ext js,jsx src scripts __tests__ __mocks__","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","build":"rollup --config","build-toc":"node ./scripts/buildToc.js","semantic-release":"semantic-release","contributors":"all-contributors generate"},"husky":{"hooks":{"pre-commit":"npm run lint","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-push":"npm t"}},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+https://github.com/RisingStack/react-easy-state.git"},"bugs":{"url":"https://github.com/RisingStack/react-easy-state/issues"},"homepage":"https://github.com/RisingStack/react-easy-state#readme","license":"MIT","keywords":["observable","react-component","react","reactjs","reactive","model","frp","functional-reactive-programming","state management","es6 proxy"],"dependencies":{"@nx-js/observer-util":"^4.2.2"},"peerDependencies":{"react":"*"},"devDependencies":{"@babel/core":"^7.8.7","@babel/plugin-proposal-class-properties":"^7.8.3","@babel/plugin-proposal-export-default-from":"^7.8.3","@babel/plugin-transform-async-to-generator":"^7.8.3","@babel/plugin-transform-modules-commonjs":"^7.8.3","@babel/polyfill":"^7.8.7","@babel/preset-env":"^7.8.7","@babel/preset-react":"^7.8.3","@commitlint/cli":"^8.3.5","@commitlint/config-angular":"^8.3.4","@rollup/plugin-node-resolve":"^7.1.1","@testing-library/jest-dom":"^5.1.1","@testing-library/react":"^10.0.1","@types/react":"^16.9.23","all-contributors-cli":"^6.14.0","babel-eslint":"^10.1.0","classnames":"^2.2.6","coveralls":"^3.0.9","eslint":"^6.8.0","eslint-config-airbnb":"^18.1.0","eslint-config-prettier":"^6.10.0","eslint-plugin-import":"^2.20.1","eslint-plugin-jsx-a11y":"^6.2.3","eslint-plugin-prettier":"^3.1.2","eslint-plugin-react":"^7.19.0","eslint-plugin-react-hooks":"^2.5.0","husky":"^4.2.3","jest":"^25.1.0","markdown-toc":"^1.2.0","moment":"^2.24.0","no-hook-react":"npm:react@16.7.0","no-hook-react-dom":"npm:react-dom@16.7.0","no-hook-react-testing-library":"npm:react-testing-library@5.4.4","nyc":"^15.0.0","prettier":"^1.19.1","react":"^16.12.0","react-dom":"^16.13.0","react-native":"^0.61.5","react-native-testing-library":"^1.12.0","react-router-dom":"^5.1.2","react-test-renderer":"^16.13.0","rollup":"^2.0.6","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.4.0","semantic-release":"^17.0.4","sinon":"^9.0.1","styled-components":"^5.0.1"},"engines":{"node":">=6.0.0"},"gitHead":"a0600a0c0c8594420ec937094b534d00ea3b82be","_id":"@risingstack/react-easy-state@6.2.1","_nodeVersion":"10.19.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-ijMWbU/GD+t3vTZ24y5DCCWK0c06Tcn3am8gmJOb3LJHtrS/uXsBfPuh8wCZ7KFq+aV7R0pnczr2rg8v0t055Q==","shasum":"2548311292c9301829c8b61ca7583b63be8c76ef","tarball":"https://registry.npmjs.org/@risingstack/react-easy-state/-/react-easy-state-6.2.1.tgz","fileCount":12,"unpackedSize":182485,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJejiQmCRA9TVsSAnZWagAA2ogP/2b9tjO9MtX8BdBY2lrv\nwV+L9B2qIRQbqgTpGFhMJoSiYrNuwhzJCDbnc3kijuRIfiGEwjuok3gNZky1\nDTPvx9FAlTu8dKhdHDnk+3VbDWjefEzuk08W7uNU0inyb4UjvFS0jcvtMk+V\n2r2mygDwb3YM9GYLUSvPWO9DYPAwmmEg7eNBOA64VzAwskt2BtHvLK4AWj+F\nnLvfpftBS+0h0ITlpoVEefzy9WBw3G5TVCPwPDEbBL7lbf0RJjMw/2YsgERH\nZ82pwrWhLeJIL5cTTwf1gH8uzKUFnhrL/IxjDZNCYQCIbDj7gykdB/C/Ls8J\nJHMz/b/9Yiu7h5udVebzoVWyvsT5WRqr/oVCovjEzbKn++H74AnWhOfpMraS\nJjUIzLueWWWi+menZDHGvjgMi8urx0jwNwliqeIPKDz9eHJLv0W4+gFn/TPA\n91WEmpDj6ic2RcAzeQTL56Rfr4q6DRfrYRPBjhkkabd/ZAWhIvH8pOzW/hF1\nxNykPcvMo4zdhwzJt9opCFY7ltg50jYNK5h3ymyN7FcUnCOMRJnMhNiB0AFY\nWUi09bmdKks/mVVNun2VU2j66vC00sACYi/4a0LDzrpLi0biNYNdU3An98/u\n7nXcYCNG2phQMGTO/irrWwQRiNNtyetceTsuA1kmUgrsjKifZYKpQkTmUcaQ\nupur\r\n=oqSs\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBLhs5KJDbLbqfItbNp424nsUN4HjXsQZ+KeCZgHjWz9AiEA7OwYSXYrBJiVcMS0O2DWxyTRbK37NwLOJ0JiENPv3h8="}]},"maintainers":[{"name":"dandesz198","email":"dandesz198@gmail.com"},{"name":"fwalkwithm","email":"fwalkwithm@gmail.com"},{"name":"gergelyke","email":"mail@nemethgergely.com"},{"name":"hekike","email":"email@martonpeter.com"},{"name":"jota","email":"simonzsoltjota@gmail.com"},{"name":"kubischj","email":"kubischj@windowslive.com"},{"name":"ozonid","email":"david@risingstack.com"},{"name":"paldiana01","email":"diana.pal@risingstack.com"},{"name":"peteyycz","email":"p.czibik@gmail.com"},{"name":"risingnpm","email":"info@risingstack.com"},{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},{"name":"tamas.hodi","email":"tamas.hodi89@gmail.com"}],"_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.2.1_1586373670109_0.40429729892087796"},"_hasShrinkwrap":false},"6.2.2":{"name":"@risingstack/react-easy-state","version":"6.2.2","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es6.js","module":"dist/es.es6.js","types":"types/index.d.ts","scripts":{"test-native":"NATIVE=true jest --config ./jest.native.json --silent","test-web":"jest --config ./jest.web.json --silent","test-web-no-hook":"NOHOOK=true jest --config ./jest.no-hook.json --silent","test":"npm run test-web && npm run test-web-no-hook && npm run test-native","example":"node ./scripts/startExample.js","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"eslint --max-warnings 0 --ext js,jsx src scripts __tests__ __mocks__","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","build":"rollup --config","build-toc":"node ./scripts/buildToc.js","semantic-release":"semantic-release","contributors":"all-contributors generate"},"husky":{"hooks":{"pre-commit":"npm run lint","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-push":"npm t"}},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+https://github.com/RisingStack/react-easy-state.git"},"bugs":{"url":"https://github.com/RisingStack/react-easy-state/issues"},"homepage":"https://github.com/RisingStack/react-easy-state#readme","license":"MIT","keywords":["observable","react-component","react","reactjs","reactive","model","frp","functional-reactive-programming","state management","es6 proxy"],"dependencies":{"@nx-js/observer-util":"^4.2.2"},"peerDependencies":{"react":"*"},"devDependencies":{"@babel/core":"^7.8.7","@babel/plugin-proposal-class-properties":"^7.8.3","@babel/plugin-proposal-export-default-from":"^7.8.3","@babel/plugin-transform-async-to-generator":"^7.8.3","@babel/plugin-transform-modules-commonjs":"^7.8.3","@babel/polyfill":"^7.8.7","@babel/preset-env":"^7.8.7","@babel/preset-react":"^7.8.3","@commitlint/cli":"^8.3.5","@commitlint/config-angular":"^8.3.4","@rollup/plugin-node-resolve":"^7.1.1","@testing-library/jest-dom":"^5.1.1","@testing-library/react":"^10.0.1","@types/react":"^16.9.23","all-contributors-cli":"^6.14.0","babel-eslint":"^10.1.0","classnames":"^2.2.6","coveralls":"^3.0.9","eslint":"^6.8.0","eslint-config-airbnb":"^18.1.0","eslint-config-prettier":"^6.10.0","eslint-plugin-import":"^2.20.1","eslint-plugin-jsx-a11y":"^6.2.3","eslint-plugin-prettier":"^3.1.2","eslint-plugin-react":"^7.19.0","eslint-plugin-react-hooks":"^2.5.0","husky":"^4.2.3","jest":"^25.1.0","markdown-toc":"^1.2.0","moment":"^2.24.0","no-hook-react":"npm:react@16.7.0","no-hook-react-dom":"npm:react-dom@16.7.0","no-hook-react-testing-library":"npm:react-testing-library@5.4.4","nyc":"^15.0.0","prettier":"^1.19.1","react":"^16.12.0","react-dom":"^16.13.0","react-native":"^0.61.5","react-native-testing-library":"^1.12.0","react-router-dom":"^5.1.2","react-test-renderer":"^16.13.0","rollup":"^2.0.6","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.4.0","semantic-release":"^17.0.4","sinon":"^9.0.1","styled-components":"^5.0.1"},"engines":{"node":">=6.0.0"},"gitHead":"ac78b3ca5ef284d7728ab324107b7a6ab7b8045c","_id":"@risingstack/react-easy-state@6.2.2","_nodeVersion":"10.20.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-ruyLKiyRUlZsZU40Nokljh14roigAsdv6gl9FN40DplT+NnzHmnHuKs7eaujAVmcmn909qf1hMLsZwSJzbPWvQ==","shasum":"325083bc3807eed19c6b2ebf790d9de36b6588ca","tarball":"https://registry.npmjs.org/@risingstack/react-easy-state/-/react-easy-state-6.2.2.tgz","fileCount":12,"unpackedSize":182638,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeldtdCRA9TVsSAnZWagAADTwP/1OBq6eIEAY3Lcsu6oMs\n5HviEFg2aHUXwX8wf9DRV7j34A8u8pZzgN3Bell0+EPVjXFbduocvucY6QHY\nzBiedWI4SEjMmf3q7ihZntjMx51daMD9h1Dt3OWwxEdaUJb0/XmdNTnyAWoP\nf4fngl/qkmfhPFsQXU01lxOcl8rUa0IT3Y9SPMX+Zis7B/DNZ/pnvLpNB+RR\nay9sU9AsGypC55VUnVzchtCggA40zGDBYFhHWIjfdTk2oEJttqhgwCmc7ARd\nekAJxVUfZx2rOQT07DJqA9nEhQ4TBF3CKSNKFgBs+nhDirfv4W9qPVJBZa+M\nSlwEenIOg9gsB5fE2H98MgRT7CNr7QqREtNHxTCqr8y1vgOS72lLJXleQXM2\n+TIr98iPUY1Ffau7PcmDAqUhV261spKhT6selizf0PsSlB1v4oAH2HVJpO9k\nlssWK0yRAhOlEUgp5AGXfbLGUNBfi6kDvWW3C6wQxVWP6YvzJSxL/Brk0xrq\nCA5+t/BOAR9jw8uUU+vE43UHozHIwOPJ0LBWmAeB6fc5XLnB1LqVZ6fLKtk0\n5ViqS5mBKnBR2vvFQpf1k4znRYJt1S9J84o1/ljSgkUG6HTFAKjiASQIIk2D\n/LH94pKjIg0iSt/Mg18sd8Ym0B4E6S/PflrzF32bLHGOnJHvpobB2Y6SJ+Re\nx38/\r\n=2Ltc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCBTtoil9WWQtYRQSjrf6r+7TMo5q6LOZDurAtgbmyP2QIhALKuC1cPEHtoIz90mEPQjtTKxH/X8dr5lok5sSEfmXfX"}]},"maintainers":[{"name":"dandesz198","email":"dandesz198@gmail.com"},{"name":"fwalkwithm","email":"fwalkwithm@gmail.com"},{"name":"gergelyke","email":"mail@nemethgergely.com"},{"name":"hekike","email":"email@martonpeter.com"},{"name":"jota","email":"simonzsoltjota@gmail.com"},{"name":"kubischj","email":"kubischj@windowslive.com"},{"name":"ozonid","email":"david@risingstack.com"},{"name":"paldiana01","email":"diana.pal@risingstack.com"},{"name":"peteyycz","email":"p.czibik@gmail.com"},{"name":"risingnpm","email":"info@risingstack.com"},{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},{"name":"tamas.hodi","email":"tamas.hodi89@gmail.com"}],"_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.2.2_1586879324865_0.2630754876427188"},"_hasShrinkwrap":false},"6.2.3":{"name":"@risingstack/react-easy-state","version":"6.2.3","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es6.js","module":"dist/es.es6.js","types":"types/index.d.ts","scripts":{"test-native":"NATIVE=true jest --config ./jest.native.json --silent","test-web":"jest --config ./jest.web.json --silent","test-web-no-hook":"NOHOOK=true jest --config ./jest.no-hook.json --silent","test":"npm run test-web && npm run test-web-no-hook && npm run test-native","example":"node ./scripts/startExample.js","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"eslint --max-warnings 0 --ext js,jsx src scripts __tests__ __mocks__","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","build":"rollup --config","build-toc":"node ./scripts/buildToc.js","semantic-release":"semantic-release","contributors":"all-contributors generate"},"husky":{"hooks":{"pre-commit":"npm run lint","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-push":"npm t"}},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+https://github.com/RisingStack/react-easy-state.git"},"bugs":{"url":"https://github.com/RisingStack/react-easy-state/issues"},"homepage":"https://github.com/RisingStack/react-easy-state#readme","license":"MIT","keywords":["observable","react-component","react","reactjs","reactive","model","frp","functional-reactive-programming","state management","es6 proxy"],"dependencies":{"@nx-js/observer-util":"^4.2.2"},"peerDependencies":{"react":"*"},"devDependencies":{"@babel/core":"^7.8.7","@babel/plugin-proposal-class-properties":"^7.8.3","@babel/plugin-proposal-export-default-from":"^7.8.3","@babel/plugin-transform-async-to-generator":"^7.8.3","@babel/plugin-transform-modules-commonjs":"^7.8.3","@babel/polyfill":"^7.8.7","@babel/preset-env":"^7.8.7","@babel/preset-react":"^7.8.3","@commitlint/cli":"^8.3.5","@commitlint/config-angular":"^8.3.4","@rollup/plugin-node-resolve":"^7.1.1","@testing-library/jest-dom":"^5.1.1","@testing-library/react":"^10.0.1","@types/react":"^16.9.23","all-contributors-cli":"^6.14.0","babel-eslint":"^10.1.0","classnames":"^2.2.6","coveralls":"^3.0.9","eslint":"^6.8.0","eslint-config-airbnb":"^18.1.0","eslint-config-prettier":"^6.10.0","eslint-plugin-import":"^2.20.1","eslint-plugin-jsx-a11y":"^6.2.3","eslint-plugin-prettier":"^3.1.2","eslint-plugin-react":"^7.19.0","eslint-plugin-react-hooks":"^2.5.0","husky":"^4.2.3","jest":"^25.1.0","markdown-toc":"^1.2.0","moment":"^2.24.0","no-hook-react":"npm:react@16.7.0","no-hook-react-dom":"npm:react-dom@16.7.0","no-hook-react-testing-library":"npm:react-testing-library@5.4.4","nyc":"^15.0.0","prettier":"^1.19.1","react":"^16.12.0","react-dom":"^16.13.0","react-native":"^0.61.5","react-native-testing-library":"^1.12.0","react-router-dom":"^5.1.2","react-test-renderer":"^16.13.0","rollup":"^2.0.6","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.4.0","semantic-release":"^17.0.4","sinon":"^9.0.1","styled-components":"^5.0.1"},"engines":{"node":">=6.0.0"},"gitHead":"45bce1f33ecf211b1ab9cbd4086b0684a5bf87fc","_id":"@risingstack/react-easy-state@6.2.3","_nodeVersion":"10.20.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-v1F5LnlG+RJAqwReWWYWclo6A1kqNx66AK0e4AXRjpHAL/RBuSLT8PX6nVOAJqgCD94iYfpMwfxOaW1i8VU3hQ==","shasum":"061bc04aa1b3e1767ea264ba2144dc75ddcbefa8","tarball":"https://registry.npmjs.org/@risingstack/react-easy-state/-/react-easy-state-6.2.3.tgz","fileCount":12,"unpackedSize":182654,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeldzdCRA9TVsSAnZWagAA/+AP+wZ8/tdE6UCTzEmIM8wQ\nKMSx1R8q1L4ApinpD5X/H4bg90D3EcPhboEHt3M+BAvuUPDqP9I4QO/UoZdy\n36EDemdCBZl+C7jTMeTjeaVBIun9d4YidxHrrDLEIc1KVLGQ6BkR9qUiZlvZ\nQLawk7NvaDONyf69ch8wyYhr1CI3+R43r8DqmP43ou6OWA0Xlj/4e6O6eMCK\nRkjX9aVF9+LZdAlsZyNTuhAJougUVuX9viULZrNcUUOoOLi8Y5jm9XP7kPE4\nKq/K156QdFhaRNhrU1MioT9v864V1nWy47PB7TKd9htaLVk44PaYPU/P/J2Z\nOeTkb96zw+CIuPomSrCwEHG/liFsejM0JGAcIdT7/kV9IwHfaI29sO8uIots\nJj0Zvv5dhm4WslcTPtBYtgIS8xJBiJvOoCieFbM/z/jflMKmozqBRjFD7iaN\nKJqIV+ABnFs534BB1FS3b1/W/uuoowyR0KNf4p5deNfum4y1RWDg8FGpDyeV\nPAiRY0yXSLt6IbVfUnBSTZdvTucW9rRuR5wBHmR13YG9hI+Qmm2tODIsJqSa\nLirGNMUDPRUlpJmj2I4xutOLGbBxZ378SOztC+c0QTLMuZKZxNPRG1FVsrcJ\nyGzigTOdZWwMBL9CEibspWV6yVTJwaftcV9oANeKO5QFQuQ2bKAiTS2+yk0y\nM3tY\r\n=S7Dy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC5YrajLcJU7Avo97Bd/PcUgM8ZZowS/KPfFl1f5EZhAwIgJRV5RjMeVnVusVsbMGFqQXWGZ0SVHxU5s9Pv5l+7cQk="}]},"maintainers":[{"name":"dandesz198","email":"dandesz198@gmail.com"},{"name":"fwalkwithm","email":"fwalkwithm@gmail.com"},{"name":"gergelyke","email":"mail@nemethgergely.com"},{"name":"hekike","email":"email@martonpeter.com"},{"name":"jota","email":"simonzsoltjota@gmail.com"},{"name":"kubischj","email":"kubischj@windowslive.com"},{"name":"ozonid","email":"david@risingstack.com"},{"name":"paldiana01","email":"diana.pal@risingstack.com"},{"name":"peteyycz","email":"p.czibik@gmail.com"},{"name":"risingnpm","email":"info@risingstack.com"},{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},{"name":"tamas.hodi","email":"tamas.hodi89@gmail.com"}],"_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.2.3_1586879708554_0.5044491664302808"},"_hasShrinkwrap":false},"6.2.4":{"name":"@risingstack/react-easy-state","version":"6.2.4","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es6.js","module":"dist/es.es6.js","types":"types/index.d.ts","scripts":{"test-native":"NATIVE=true jest --config ./jest.native.json --silent","test-web":"jest --config ./jest.web.json --silent","test-web-no-hook":"NOHOOK=true jest --config ./jest.no-hook.json --silent","test":"npm run test-web && npm run test-web-no-hook && npm run test-native","example":"node ./scripts/startExample.js","test-node-support":"node ./scripts/testNode.js","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"eslint --max-warnings 0 --ext js,jsx src scripts __tests__ __mocks__","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","build":"rollup --config","build-toc":"node ./scripts/buildToc.js","semantic-release":"semantic-release","contributors":"all-contributors generate"},"husky":{"hooks":{"pre-commit":"npm run lint","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-push":"npm t"}},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+https://github.com/RisingStack/react-easy-state.git"},"bugs":{"url":"https://github.com/RisingStack/react-easy-state/issues"},"homepage":"https://github.com/RisingStack/react-easy-state#readme","license":"MIT","keywords":["observable","react-component","react","reactjs","reactive","model","frp","functional-reactive-programming","state management","es6 proxy"],"dependencies":{"@nx-js/observer-util":"^4.2.2"},"peerDependencies":{"react":"*"},"devDependencies":{"@babel/core":"^7.8.7","@babel/plugin-proposal-class-properties":"^7.8.3","@babel/plugin-proposal-export-default-from":"^7.8.3","@babel/plugin-proposal-object-rest-spread":"^7.9.5","@babel/plugin-transform-async-to-generator":"^7.8.3","@babel/plugin-transform-modules-commonjs":"^7.8.3","@babel/polyfill":"^7.8.7","@babel/preset-env":"^7.8.7","@babel/preset-react":"^7.8.3","@commitlint/cli":"^8.3.5","@commitlint/config-angular":"^8.3.4","@rollup/plugin-node-resolve":"^7.1.1","@testing-library/jest-dom":"^5.1.1","@testing-library/react":"^10.0.1","@types/react":"^16.9.23","all-contributors-cli":"^6.14.0","babel-eslint":"^10.1.0","classnames":"^2.2.6","coveralls":"^3.0.9","eslint":"^6.8.0","eslint-config-airbnb":"^18.1.0","eslint-config-prettier":"^6.10.0","eslint-plugin-import":"^2.20.1","eslint-plugin-jsx-a11y":"^6.2.3","eslint-plugin-prettier":"^3.1.2","eslint-plugin-react":"^7.19.0","eslint-plugin-react-hooks":"^2.5.0","husky":"^4.2.3","jest":"^25.1.0","markdown-toc":"^1.2.0","moment":"^2.24.0","no-hook-react":"npm:react@16.7.0","no-hook-react-dom":"npm:react-dom@16.7.0","no-hook-react-testing-library":"npm:react-testing-library@5.4.4","nyc":"^15.0.0","prettier":"^1.19.1","react":"^16.12.0","react-dom":"^16.13.0","react-native":"^0.61.5","react-native-testing-library":"^1.12.0","react-router-dom":"^5.1.2","react-test-renderer":"^16.13.0","rollup":"^2.0.6","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.4.0","semantic-release":"^17.0.4","sinon":"^9.0.1","styled-components":"^5.0.1"},"engines":{"node":">=6.0.0"},"gitHead":"0bc26e5a7a8d3caec953cd7fcdd70ba03692b05d","_id":"@risingstack/react-easy-state@6.2.4","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-a0SKhrsVy3+GDch+j7xKidEXPzc6RVpfS1eCs/dWZn6r808H3tCeOYjj3kiDyd8I3b7meVskGhC1XjW05Y3rgw==","shasum":"458328f3fca77bc12dfbc44a77ed88e66ef8dfc6","tarball":"https://registry.npmjs.org/@risingstack/react-easy-state/-/react-easy-state-6.2.4.tgz","fileCount":12,"unpackedSize":184758,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJenNneCRA9TVsSAnZWagAATzsP/2nfDGn+rOpsIrQecQyN\ntPg3htBGQyjEgS9z0NmBvuzT2Cds04m+kh15n9QuCJjjlWxE3yfGmd/tW+/j\nNeQzGB1AdCgZKdqZPBWzor0mhc5Pql4HKF0VbIX5sgBMO2hI05yVWJCtxxJE\nN8VM9xFUb6WINVsYReIVRrPmfqdmz+/1si7ljUgpN1LJgaMgZ6OGLnyTeXwp\n+85XHEJNn1tB5LPux7XfME76Euz1ABVkKOvfesQ0d7nWkUV7iWDN0p4j1V8m\n32yM0a0UUE91cnQ1WmlgP5PBATOPvWP751REWlNTpDEsG0VfN92Flp7HAqAM\n9L4/5hv8tnT15tNvUTOUILyO2qEH/VkJOYl5Q8f4k+I02w9m6JzoZ+b0liXQ\nz/St8iWKeyL3s+c828R0QkmR4eb5gsLy8mdkKxxRy9u7cuHsTCgY/R3+ofTj\ne8HVHG+VNhTUxWjW5oz4jWbuYJ+JF3zblaVU5TqZbbpf6/y0bH3yTEIv+9r1\na75KFx5a5hH84E8GzrICyu6PnapwKK+XgCN9oO2lq2Tx1kBSp378q48/QFmu\nnSzxVMi8bfF9A9JwwC9pgNAojpLfxVpgwynyWHp/MX2ivIhPbcuMo6nUeWDQ\nBxWQi5lQ9Fv0GXTAgVpyeRthKEbCjpkevBaswmdIUfu9nYfD+Rzs+GFBjhMx\nlwaj\r\n=hxqO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDuBWo0lpIL6Z6qtxrKemzj9Wtj9Wnld/aKeKOYGvhhFQIhAL9F+Lg503Fa79ZP7J1h/+sRKnZUHJvmkEjXC5PIv6U9"}]},"maintainers":[{"name":"dandesz198","email":"dandesz198@gmail.com"},{"name":"fwalkwithm","email":"fwalkwithm@gmail.com"},{"name":"gergelyke","email":"mail@nemethgergely.com"},{"name":"hekike","email":"email@martonpeter.com"},{"name":"jota","email":"simonzsoltjota@gmail.com"},{"name":"kubischj","email":"kubischj@windowslive.com"},{"name":"ozonid","email":"david@risingstack.com"},{"name":"paldiana01","email":"diana.pal@risingstack.com"},{"name":"peteyycz","email":"p.czibik@gmail.com"},{"name":"risingnpm","email":"info@risingstack.com"},{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},{"name":"tamas.hodi","email":"tamas.hodi89@gmail.com"}],"_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.2.4_1587337693569_0.11905985069525715"},"_hasShrinkwrap":false},"6.3.0":{"name":"@risingstack/react-easy-state","version":"6.3.0","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es6.js","module":"dist/es.es6.js","types":"types/index.d.ts","scripts":{"test-native":"NATIVE=true jest --config ./jest.native.json --silent","test-web":"jest --config ./jest.web.json --silent","test-web-no-hook":"NOHOOK=true jest --config ./jest.no-hook.json --silent","test":"npm run test-web && npm run test-web-no-hook && npm run test-native","example":"node ./scripts/startExample.js","test-node-support":"node ./scripts/testNode.js","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"eslint --max-warnings 0 --ext js,jsx src scripts __tests__ __mocks__","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","build":"rollup --config","build-toc":"node ./scripts/buildToc.js","semantic-release":"semantic-release","contributors":"all-contributors generate"},"husky":{"hooks":{"pre-commit":"npm run lint","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-push":"npm t"}},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+https://github.com/RisingStack/react-easy-state.git"},"bugs":{"url":"https://github.com/RisingStack/react-easy-state/issues"},"homepage":"https://github.com/RisingStack/react-easy-state#readme","license":"MIT","keywords":["observable","react-component","react","reactjs","reactive","model","frp","functional-reactive-programming","state management","es6 proxy"],"dependencies":{"@nx-js/observer-util":"^4.2.2"},"peerDependencies":{"react":"*"},"devDependencies":{"@babel/core":"^7.8.7","@babel/plugin-proposal-class-properties":"^7.8.3","@babel/plugin-proposal-export-default-from":"^7.8.3","@babel/plugin-proposal-object-rest-spread":"^7.9.5","@babel/plugin-transform-async-to-generator":"^7.8.3","@babel/plugin-transform-modules-commonjs":"^7.8.3","@babel/polyfill":"^7.8.7","@babel/preset-env":"^7.8.7","@babel/preset-react":"^7.8.3","@commitlint/cli":"^8.3.5","@commitlint/config-angular":"^8.3.4","@rollup/plugin-node-resolve":"^7.1.1","@testing-library/jest-dom":"^5.1.1","@testing-library/react":"^10.0.1","@types/react":"^16.9.23","all-contributors-cli":"^6.14.0","babel-eslint":"^10.1.0","classnames":"^2.2.6","coveralls":"^3.0.9","eslint":"^6.8.0","eslint-config-airbnb":"^18.1.0","eslint-config-prettier":"^6.10.0","eslint-plugin-import":"^2.20.1","eslint-plugin-jsx-a11y":"^6.2.3","eslint-plugin-prettier":"^3.1.2","eslint-plugin-react":"^7.19.0","eslint-plugin-react-hooks":"^2.5.0","husky":"^4.2.3","jest":"^25.1.0","markdown-toc":"^1.2.0","moment":"^2.24.0","no-hook-react":"npm:react@16.7.0","no-hook-react-dom":"npm:react-dom@16.7.0","no-hook-react-testing-library":"npm:react-testing-library@5.4.4","nyc":"^15.0.0","prettier":"^1.19.1","react":"^16.12.0","react-dom":"^16.13.0","react-native":"^0.61.5","react-native-testing-library":"^1.12.0","react-router-dom":"^5.1.2","react-test-renderer":"^16.13.0","rollup":"^2.0.6","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.4.0","rollup-plugin-replace":"^2.2.0","semantic-release":"^17.0.4","sinon":"^9.0.1","styled-components":"^5.0.1"},"engines":{"node":">=6.0.0"},"gitHead":"0163659f5a6d801b5d7851f331d6d525722c192e","_id":"@risingstack/react-easy-state@6.3.0","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-AGLrzvwloZL7dgagwRkxJaq7bcDsOGdHrCpHZIlMIxcFLdFr5IpD2/kcmTlC34H682pvfIl1lzNxBw72la10aA==","shasum":"3590031f7382c5c6c7866790ba7a72e557a12407","tarball":"https://registry.npmjs.org/@risingstack/react-easy-state/-/react-easy-state-6.3.0.tgz","fileCount":16,"unpackedSize":188166,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeorPPCRA9TVsSAnZWagAAgLYP/RIyaDVlv+JnT1jKZvQZ\nFssEvz395nXqorQbP94MHG9etd7AoEU1kK/nk7QL+7hnlu5FFT8VcI51WLhk\nV9DmOI1IL7RAvsQVkZ4PmXJvAKIJ//wtvYjlfYhRUFHMabOlfcQz3gv5ch3K\nJ6MpZopBPwMob8urXiYIxyNlXZCn58lZ1MaxymLBZb4OxD24MYHnYJLfKmCB\nA0kIwUqzlT9kvWh9H/m0zwvbWHWCYbK7HlC+SsJj9qN1n6dkTZnABVorAw7S\nwmq8/V0h0FZQR1+D0FLhTm+47iZpoDiH3bFvvdOV9JttV8N6S71OWVJNGvkr\nf2Z/4/Crhm8gRCEy7rs/zIeTvAsztHvoZOeJ4bTzs+nn8R9ZJOkUNpjsVNFP\n6/Re+cOk7E4XTMUR7BAYzoVEIipOq2AIO0i4JC13HSKsqnBOav8ubgMthqRu\nTQ6HiNrvSFZaENNqjeyYaLRrqgUzii2SbC3X6ulef3HkmkqNRJy3VbQhhPNs\nasD5S3fdgvWFzjXtmuoWd+IBtV0tOb3qs/LbTON1/azIsgGTxm926ObESagc\nq3rrSoX2Qy56QQDBdWgAVcBU0QXj3ZT+oHLMUy+Iz52fFBIaTYFAJXp6zVR0\nJdkXRY9eBbPONBDJoh4buNEax8ENLQ3xAsDwYSbWoFWfF0N4QfzaJLeVR8NI\n4k/I\r\n=i46q\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDRyUt94wQ49+iPh8BEPusmfMN7UJS4Yjx5wNIJC0fAbAIgN93fWYvGzYw7m3pEiXmdNtMMijMkGjMYwkrCeM7GmHE="}]},"maintainers":[{"name":"dandesz198","email":"dandesz198@gmail.com"},{"name":"fwalkwithm","email":"fwalkwithm@gmail.com"},{"name":"gergelyke","email":"mail@nemethgergely.com"},{"name":"hekike","email":"email@martonpeter.com"},{"name":"jota","email":"simonzsoltjota@gmail.com"},{"name":"kubischj","email":"kubischj@windowslive.com"},{"name":"ozonid","email":"david@risingstack.com"},{"name":"paldiana01","email":"diana.pal@risingstack.com"},{"name":"peteyycz","email":"p.czibik@gmail.com"},{"name":"risingnpm","email":"info@risingstack.com"},{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},{"name":"tamas.hodi","email":"tamas.hodi89@gmail.com"}],"_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.3.0_1587721166579_0.29450822519516007"},"_hasShrinkwrap":false},"6.4.0-alpha.1":{"name":"@risingstack/react-easy-state","version":"6.4.0-alpha.1","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es6.js","module":"dist/es.es6.js","types":"types/index.d.ts","scripts":{"test-native":"NATIVE=true jest --config ./jest.native.json --silent","test-web":"jest --config ./jest.web.json --silent","test-web-no-hook":"NOHOOK=true jest --config ./jest.no-hook.json --silent","test":"npm run test-web && npm run test-web-no-hook && npm run test-native","example":"node ./scripts/startExample.js","test-node-support":"node ./scripts/testNode.js","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"eslint --max-warnings 0 --ext js,jsx src scripts __tests__ __mocks__","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","build":"rollup --config","build-toc":"node ./scripts/buildToc.js","semantic-release":"semantic-release","contributors":"all-contributors generate"},"husky":{"hooks":{"pre-commit":"npm run lint","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-push":"npm t"}},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+https://github.com/RisingStack/react-easy-state.git"},"bugs":{"url":"https://github.com/RisingStack/react-easy-state/issues"},"homepage":"https://github.com/RisingStack/react-easy-state#readme","license":"MIT","keywords":["observable","react-component","react","reactjs","reactive","model","frp","functional-reactive-programming","state management","es6 proxy"],"dependencies":{"@nx-js/observer-util":"^4.3.0-alpha.0"},"peerDependencies":{"react":"*"},"devDependencies":{"@babel/core":"^7.8.7","@babel/plugin-proposal-class-properties":"^7.8.3","@babel/plugin-proposal-export-default-from":"^7.8.3","@babel/plugin-proposal-object-rest-spread":"^7.9.5","@babel/plugin-transform-async-to-generator":"^7.8.3","@babel/plugin-transform-modules-commonjs":"^7.8.3","@babel/polyfill":"^7.8.7","@babel/preset-env":"^7.8.7","@babel/preset-react":"^7.8.3","@commitlint/cli":"^8.3.5","@commitlint/config-angular":"^8.3.4","@rollup/plugin-node-resolve":"^7.1.1","@testing-library/jest-dom":"^5.1.1","@testing-library/react":"^10.0.1","@types/react":"^16.9.23","all-contributors-cli":"^6.14.0","babel-eslint":"^10.1.0","classnames":"^2.2.6","coveralls":"^3.0.9","eslint":"^6.8.0","eslint-config-airbnb":"^18.1.0","eslint-config-prettier":"^6.10.0","eslint-plugin-import":"^2.20.1","eslint-plugin-jsx-a11y":"^6.2.3","eslint-plugin-prettier":"^3.1.2","eslint-plugin-react":"^7.19.0","eslint-plugin-react-hooks":"^2.5.0","husky":"^4.2.3","jest":"^25.1.0","markdown-toc":"^1.2.0","moment":"^2.24.0","no-hook-react":"npm:react@16.7.0","no-hook-react-dom":"npm:react-dom@16.7.0","no-hook-react-testing-library":"npm:react-testing-library@5.4.4","nyc":"^15.0.0","prettier":"^1.19.1","react":"^16.12.0","react-dom":"^16.13.0","react-native":"^0.61.5","react-native-testing-library":"^1.12.0","react-router-dom":"^5.1.2","react-test-renderer":"^16.13.0","rollup":"^2.0.6","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.4.0","rollup-plugin-replace":"^2.2.0","semantic-release":"^17.0.4","sinon":"^9.0.1","styled-components":"^5.0.1"},"engines":{"node":">=6.0.0"},"readme":"<p align=\"center\">\n  <img src=\"images/logo.svg\" width=\"600px\" height=\"auto\" />\n</p>\n\n## React Easy State - by [RisingStack](https://risingstack.com/)\n\n[![Build](https://img.shields.io/circleci/project/github/RisingStack/react-easy-state/master.svg)](https://circleci.com/gh/RisingStack/react-easy-state/tree/master) [![dependencies Status](https://david-dm.org/RisingStack/react-easy-state/status.svg)](https://david-dm.org/RisingStack/react-easy-state) [![Coverage Status](https://coveralls.io/repos/github/RisingStack/react-easy-state/badge.svg?branch=master&service=github)](https://coveralls.io/github/RisingStack/react-easy-state?branch=master) [![Package size](https://img.shields.io/bundlephobia/minzip/@risingstack/react-easy-state.svg)](https://bundlephobia.com/result?p=@risingstack/react-easy-state) [![Version](https://img.shields.io/npm/v/@risingstack/react-easy-state.svg)](https://www.npmjs.com/package/@risingstack/react-easy-state) [![License](https://img.shields.io/npm/l/@risingstack/react-easy-state.svg)](https://www.npmjs.com/package/@risingstack/react-easy-state) <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->\n[![All Contributors](https://img.shields.io/badge/all_contributors-4-blue.svg)](#contributors)\n<!-- ALL-CONTRIBUTORS-BADGE:END -->\n\n<a href=\"#platform-support-computer\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" height=\"auto\" /></a>\n\n**NEWS:** v6.3.0 fixed a nasty bug that could render [zombie children](https://react-redux.js.org/api/hooks#stale-props-and-zombie-children). Please update to this version at least to save yourself some headaches. Thanks!\n\n<details>\n<summary><strong>Table of Contents</strong></summary>\n<!-- Do not edit the Table of Contents, instead regenerate with `npm run build-toc` -->\n\n<!-- toc -->\n\n* [Introduction :wave:](#introduction-wave)\n* [Installation :cd:](#installation-cd)\n* [Everyday Usage :sunglasses:](#everyday-usage-sunglasses)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Advanced Usage :nerd_face:](#advanced-usage-nerd_face)\n  + [Adding side effects](#adding-side-effects)\n* [API Summary :book:](#api-summary-book)\n  + [store(obj)](#storeobj)\n  + [view(Comp)](#viewcomp)\n  + [batch(fn)](#batchfn)\n  + [autoEffect(fn)](#autoeffectfn)\n  + [clearEffect(fn)](#cleareffectfn)\n* [Examples with live demos :tv:](#examples-with-live-demos-tv)\n* [Articles :loudspeaker:](#articles-loudspeaker)\n* [Performance :rocket:](#performance-rocket)\n* [Platform support :computer:](#platform-support-computer)\n* [Alternative builds :wrench:](#alternative-builds-wrench)\n* [Contributors :sparkles:](#contributors-sparkles)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction :wave:\n\nReact Easy State is a practical state management library with two functions and two accompanying rules.\n\n1.  Always wrap your components with `view()`.\n2.  Always wrap your state store objects with `store()`.\n\n```jsx\nimport React from 'react';\nimport { store, view } from '@risingstack/react-easy-state';\n\nconst counter = store({\n  num: 0,\n  increment: () => counter.num++\n});\n\nexport default view(() => (\n  <button onClick={counter.increment}>{counter.num}</button>\n));\n```\n\nThis is enough for it to automatically update your views when needed. It doesn't matter how you structure or mutate your state stores, any syntactically valid code works.\n\nCheck this [TodoMVC codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/todo-mvc?module=%2Fsrc%2FtodosStore.js) or [raw code](/examples/todo-mvc/src/todosStore.js) for a more exciting example with nested data, arrays and getter properties.\n\n## Installation :cd:\n\n`npm install @risingstack/react-easy-state`\n\n<details>\n<summary><strong>Setting up a quick project</strong></summary>\n<p></p>\n\nEasy State supports <a href=\"https://github.com/facebookincubator/create-react-app\">Create React App</a> without additional configuration. Just run the following commands to get started.\n\n```sh\nnpx create-react-app my-app\ncd my-app\nnpm install @risingstack/react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Everyday Usage :sunglasses:\n\n### Creating global stores\n\n`store` creates a state store from the passed object and returns it. A state store behaves just like the passed object. (To be precise, it is a transparent reactive proxy of the original object.)\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Rick' });\n// stores behave like normal JS objects\nuser.name = 'Bob';\n```\n\n<details>\n<summary>State stores may have arbitrary structure and they may be mutated in any syntactically valid way.</summary>\n<p></p>\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\n// stores can include any valid JS structure\n// including nested data, arrays, Maps, Sets, getters, setters, inheritance, ...\nconst user = store({\n  profile: {\n    firstName: 'Bob',\n    lastName: 'Smith',\n    get name() {\n      return `${user.profile.firstName} ${user.profile.lastName}`;\n    },\n  },\n  hobbies: ['programming', 'sports'],\n  friends: new Map(),\n});\n\n// stores may be mutated in any syntactically valid way\nuser.profile.firstName = 'Bob';\ndelete user.profile.lastName;\nuser.hobbies.push('reading');\nuser.friends.set('id', otherUser);\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Async operations can be expressed with the standard async/await syntax.</summary>\n<p></p>\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst userStore = store({\n  user: {},\n  async fetchUser() {\n    userStore.user = await fetch('/user');\n  },\n});\n\nexport default userStore;\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>State stores may import and use other state stores in their methods.</summary>\n<p></p>\n\n_userStore.js_\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst userStore = store({\n  user: {},\n  async fetchUser() {\n    userStore.user = await fetch('/user');\n  },\n});\n\nexport default userStore;\n```\n\n_recipesStore.js_\n\n```js\nimport { store } from '@risingstack/react-easy-state';\nimport userStore from './userStore';\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(\n      `/recipes?user=${userStore.user.id}`,\n    );\n  },\n});\n\nexport default recipesStore;\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Wrap your state stores with <code>store</code> as early as possible.</summary>\n<p></p>\n\n```js\n// DON'T DO THIS\nconst person = { name: 'Bob' };\nperson.name = 'Ann';\n\nexport default store(person);\n```\n\n```js\n// DO THIS INSTEAD\nconst person = store({ name: 'Bob' });\nperson.name = 'Ann';\n\nexport default person;\n```\n\nThe first example wouldn't trigger re-renders on the `person.name = 'Ann'` mutation, because it is targeted at the raw object. Mutating the raw - none `store`-wrapped object - won't schedule renders.\n\n</details>\n<p></p>\n\n<details>\n<summary>Avoid using the <code>this</code> keyword in the methods of your state stores.</summary>\n<p></p>\n\n```jsx\nimport { store, view } from '@risingstack/react-easy-state';\n\nconst counter = store({\n  num: 0,\n  increment() {\n    // DON'T DO THIS\n    this.num++;\n    // DO THIS INSTEAD\n    counter.num++;\n  },\n});\n\nexport default view(() => (\n  <div onClick={counter.increment}>{counter.num}</div>\n));\n```\n\n`this.num++` won't work, because `increment` is passed as a callback and loses its `this`. You should use the direct object reference - `counter` - instead of `this`.\n\n</details>\n\n### Creating reactive views\n\nWrapping your components with `view` turns them into reactive views. A reactive view re-renders whenever a piece of store - used inside its render - changes.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\n// this is a global state store\nconst user = store({ name: 'Bob' });\n\n// this is re-rendered whenever user.name changes\nexport default view(() => (\n  <div>\n    <input\n      value={user.name}\n      onChange={ev => (user.name = ev.target.value)}\n    />\n    <div>Hello {user.name}!</div>\n  </div>\n));\n```\n\n<details>\n<summary><strong>Wrap ALL of your components with <code>view</code> - including class and function ones - even if they don't seem to directly use a store.</strong></summary>\n<p></p>\n\nEvery component that is using a store or part of a store inside its render must be wrapped with `view`. Sometimes store usage is not so explicit and easy to to miss.\n\n```jsx\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst appStore = store({\n  user: { name: 'Ann' },\n});\n\nconst App = view(() => (\n  <div>\n    <h1>My App</h1>\n    <Profile user={appStore.user} />\n  </div>\n));\n\n// DO THIS\nconst Profile = view(({ user }) => <p>Name: {user.name}</p>);\n\n// DON'T DO THIS\n// This won't re-render on appStore.user.name = 'newName' like mutations\nconst Profile = ({ user }) => <p>Name: {user.name}</p>;\n```\n\nIf you are **100% sure** that your component is not using any stores you can skip the `view` wrapper.\n\n```jsx\nimport React from 'react';\n\n// you don't have to wrap this component with `view`\nexport default (() => <p>This is just plain text</p>);\n```\n\n`view` wrapping is advised even in these cases though.\n\n- It saves you from future headaches as your project grows and you start to use stores inside these components.\n- `view` is pretty much equivalent to `memo` if you don't use any stores. That is nearly always nice to have.\n\n</details>\n<p></p>\n\n<details>\n<summary>A single reactive component may use multiple stores inside its render.</summary>\n<p></p>\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' });\nconst timeline = store({ posts: ['react-easy-state'] });\n\n// this is re-rendered whenever user.name or timeline.posts[0] changes\nexport default view(() => (\n  <div>\n    <div>Hello {user.name}!</div>\n    <div>Your first post is: {timeline.posts[0]}</div>\n  </div>\n));\n```\n\n</details>\n<p></p>\n\n<details>\n<summary><code>view</code> implements an optimal <code>shouldComponentUpdate</code> (or <code>memo</code>) for your components.</summary>\n<p></p>\n\n- Using `PureComponent` or `memo` will provide no additional performance benefits.\n\n- Defining a custom `shouldComponentUpdate` may rarely provide performance benefits when you apply some use case specific heuristics inside it.\n\n</details>\n<p></p>\n\n<details>\n<summary>Reactive renders are batched. Multiple synchronous store mutations won't result in multiple re-renders of the same component.</summary>\n<p></p>\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob', age: 30 });\n\nfunction mutateUser() {\n  user.name = 'Ann';\n  user.age = 32;\n}\n\n// calling `mutateUser` will only trigger a single re-render of the below component\n// even though it mutates the store two times in quick succession\nexport default view(() => (\n  <div onClick={mutateUser}>\n    name: {user.name}, age: {user.age}\n  </div>\n));\n```\n\nIf you mutate your stores multiple times synchronously from **exotic task sources**, multiple renders may rarely happen. If you experience performance issues you can batch changes manually with the `batch` function. `batch(fn)` executes the passed function immediately and batches any subsequent re-renders until the function execution finishes.\n\n```jsx\nimport React from 'react';\nimport { view, store, batch } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob', age: 30 });\n\nfunction mutateUser() {\n  // this makes sure the state changes will cause maximum one re-render,\n  // no matter where this function is getting invoked from\n  batch(() => {\n    user.name = 'Ann';\n    user.age = 32;\n  });\n}\n\nexport default view(() => (\n  <div>\n    name: {user.name}, age: {user.age}\n  </div>\n));\n```\n\n> **NOTE:** The React team plans to improve render batching in the future. The `batch` function and built-in batching may be deprecated and removed in the future in favor of React's own batching.\n\n</details>\n<p></p>\n\n<details>\n<summary>Always apply <code>view</code> as the latest (innermost) wrapper when you combine it with other Higher Order Components.</summary>\n<p></p>\n\n```jsx\nimport { view } from '@risingstack/react-easy-state';\nimport { withRouter } from 'react-router-dom';\nimport { withTheme } from 'styled-components';\n\nconst Comp = () => <div>A reactive component</div>;\n\n// DO THIS\nwithRouter(view(Comp));\nwithTheme(view(Comp));\n\n// DON'T DO THIS\nview(withRouter(Comp));\nview(withTheme(Comp));\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Usage with (pre v4.4) React Router.</summary>\n<p></p>\n\n- If routing is not updated properly, wrap your `view(Comp)` - with the `Route`s inside - in `withRouter(view(Comp))`. This lets react-router know when to update.\n\n- The order of the HOCs matter, always use `withRouter(view(Comp))`.\n\nThis is not necessary if you use React Router 4.4+. You can find more details and some reasoning about this in [this react-router docs page](https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md).\n\n</details>\n<p></p>\n\n<details>\n<summary>Usage with React Developer Tools.</summary>\n<p></p>\n\nIf you want React Developer Tools to recognize your reactive view components' names, you have to pass either a **named function** or an anonymous function with **name inference** to the `view` wrapper.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({\n  name: 'Rick',\n});\n\nconst componentName = () => (\n  <div>{user.name}</div>\n);\n\nexport default view(componentName);\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Passing nested data to third party components.</summary>\n<p></p>\n\nThird party helpers - like data grids - may consist of many internal components which can not be wrapped by `view`, but sometimes you would like them to re-render when the passed data mutates. Traditional React components re-render when their props change by reference, so mutating the passed reactive data won't work in these cases. You can solve this issue by deep cloning the observable data before passing it to the component. This creates a new reference for the consuming component on every store mutation.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\nimport Table from 'rc-table';\nimport cloneDeep from 'lodash/cloneDeep';\n\nconst dataStore = store({\n  items: [\n    {\n      product: 'Car',\n      value: 12,\n    },\n  ],\n});\n\nexport default view(() => (\n  <Table data={cloneDeep(dataStore.items)} />\n));\n```\n\n</details>\n\n### Creating local stores\n\nA singleton global store is perfect for something like the current user, but sometimes having local component states is a better fit. Just create a store inside a function component or as a class component property in these cases.\n\n#### Local stores in function components\n\n```jsx\nimport React from 'react'\nimport { view, store } from '@risingstack/react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  const increment = () => counter.num++\n  return <button={increment}>{counter.num}</button>\n})\n```\n\n**Local stores in functions rely on React hooks. They require React and React DOM v16.8+ or React Native v0.59+ to work.**\n\n<details>\n<summary>You can use React hooks - including <code>useState</code> - in function components, Easy State won't interfere with them. Consider using <a href=\"#local-auto-effects-in-function-components\">autoEffect</a> instead of the <code>useEffect</code> hook for the best experience though.</summary>\n<p></p>\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nexport default view(() => {\n  const [name, setName] = useState('Ann');\n  const user = store({ age: 30 });\n  return (\n    <div>\n      <input value={name} onChange={ev => setName(ev.target.value)} />\n      <input\n        value={user.age}\n        onChange={ev => (user.age = ev.target.value)}\n      />\n    </div>\n  );\n});\n```\n\n</details>\n\n#### Local stores in class components\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass Counter extends Component {\n  counter = store({ num: 0 });\n  increment = () => counter.num++;\n\n  render() {\n    return (\n      <button onClick={this.increment}>{this.counter.num}</button>\n    );\n  }\n}\n\nexport default view(Counter);\n```\n\n<details>\n<summary>You can also use vanilla <code>setState</code> in your class components, Easy State won't interfere with it.</summary>\n<p></p>\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass Profile extends Component {\n  state = { name: 'Ann' };\n  user = store({ age: 30 });\n\n  setName = ev => this.setState({ name: ev.target.value });\n  setAge = ev => (this.user.age = ev.target.value);\n\n  render() {\n    return (\n      <div>\n        <input value={this.state.name} onChange={this.setName} />\n        <input value={this.user.age} onChange={this.setAge} />\n      </div>\n    );\n  }\n}\n\nexport default view(Profile);\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Don't name local stores as <code>state</code>. It may conflict with linter rules, which guard against direct state mutations.</summary>\n<p></p>\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass Profile extends Component {\n  // DON'T DO THIS\n  state = store({});\n  // DO THIS\n  user = store({});\n  render() {}\n}\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Deriving local stores from props (<code>getDerivedStateFromProps</code>).</summary>\n<p></p>\n\nClass components wrapped with `view` have an extra static `deriveStoresFromProps` lifecycle method, which works similarly to the vanilla `getDerivedStateFromProps`.\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass NameCard extends Component {\n  userStore = store({ name: 'Bob' });\n\n  static deriveStoresFromProps(props, userStore) {\n    userStore.name = props.name || userStore.name;\n  }\n\n  render() {\n    return <div>{this.userStore.name}</div>;\n  }\n}\n\nexport default view(NameCard);\n```\n\nInstead of returning an object, you should directly mutate the received stores. If you have multiple local stores on a single component, they are all passed as arguments - in their definition order - after the first props argument.\n\n</details>\n\n## Advanced Usage :nerd_face:\n\n### Adding side effects\n\nUse `autoEffect` to react with automatic side effect to your store changes. Auto effects should contain end-of-chain logic - like changing the document title or saving data to LocalStorage. `view` is a special auto effect that does rendering.\n\n<details>\n<summary>Never use auto effects to derive data from other data. Use dynamic getters instead.</summary>\n<p></p>\n\n```jsx\nimport { store, autoEffect } from '@risingstack/react-easy-state';\n\n// DON'T DO THIS\nconst store1 = store({ name: 'Store 1' })\nconst store2 = store({ name: 'Store 2' })\nautoEffect(() => store2.name = store1.name)\n\n// DO THIS INSTEAD\nconst store1 = store({ name: 'Store 1' })\nconst store2 = store({ get name () { return store1.name } })\n```\n\n</details>\n<p></p>\n\n#### Global auto effects\n\nGlobal auto effects can be created with `autoEffect` and cleared up with `clearEffect`.\n\n```jsx\nimport { store, autoEffect, clearEffect } from '@risingstack/react-easy-state';\n\nconst app = store({ name: 'My App' })\nconst effect = autoEffect(() => document.title = app.name)\n\n// this also updates the document title\napp.name = 'My Awesome App'\n\nclearEffect(effect)\n// this won't update the document title, the effect is cleared\napp.name = 'My App'\n```\n\n#### Local auto effects in function components\n\nUse local auto effects in function components instead of the `useEffect` hook when reactive stores are used inside them. These local effects are automatically cleared when the component unmounts.\n\n```jsx\nimport React from 'react'\nimport { store, view, autoEffect } from '@risingstack/react-easy-state';\n\nexport default view(() => {\n  const app = store({ name: 'My App' })\n  // no need to clear the effect\n  autoEffect(() => document.title = app.name)\n})\n```\n\n<details>\n<summary>Explicitly pass none reactive dependencies - like vanillas props and state - to local auto effects in function components.</summary>\n<p></p>\n\nBecause of the design of React hooks you have to explicitly pass all none reactive data to a hook-like dependency array. This makes sure that the effect also runs when the none reactive data changes.\n\n```jsx\nimport React from 'react'\nimport { store, view, autoEffect } from '@risingstack/react-easy-state';\n\nexport default view(({ greeting }) => {\n  const app = store({ name: 'My App' })\n  // pass `greeting` in the dependency array because it is not coming from a store\n  autoEffect(() => document.title = `${greeting} ${app.name}`, [greeting])\n})\n```\n\n</details>\n<p></p>\n\n#### Local auto effects in class components\n\nLocal effects in class components must be cleared when the component unmounts.\n\n```jsx\nimport React, { Component } from 'react'\nimport { store, view, autoEffect } from '@risingstack/react-easy-state';\n\nclass App extends Component {\n  app = store({ name: 'My App' })\n\n  componentDidMount () {\n    this.effect = autoEffect(() => document.title = this.app.name)\n  }\n\n  componentWillUnmount () {\n    // local effects in class components must be cleared on unmount\n    clearEffect(this.effect)\n  }\n}\n```\n\n## API Summary :book:\n\n### store(obj)\n\nCreates an observable store from the passed object and returns it. Can be used outside components for [global stores](#creating-global-stores) and inside components for [local stores]((#creating-local-stores)).\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Rick' });\n```\n\n### view(Comp)\n\nCreates a [reactive view](#creating-reactive-views) from the passed component and returns it. A reactive view re-renders whenever any store data used inside it is mutated.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' });\n\nexport default view(() => (\n  <div>Hello {user.name}!</div>\n));\n```\n\n### batch(fn)\n\nImmediately executes the passed function and batches all store mutations inside it. Batched mutations are guaranteed to not trigger unnecessary double renders. Most task sources are batched automatically, only  use `batch` if you encounter performance issues.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' });\n\nfunction setName() {\n  batch(() => {\n    user.name = 'Rick'\n    user.name = 'Ann'\n  })\n}\n```\n\n### autoEffect(fn)\n\nCreates a reactive function from the passed one, immediately executes it, and returns it. A reactive function automatically re-reruns whenever any store data used inside it is mutated.\n\nCan be used both [outside](#global-auto-effects) and [inside](#local-auto-effects-in-function-components) components.\n\n```js\nimport { store, autoEffect } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' })\n\nautoEffect(() => document.title = user.name)\n```\n\n### clearEffect(fn)\n\nTakes a reactive function (returned by `autoEffect`) and clears the reactivity from it. Cleared reactive functions will no longer re-rerun on related store mutations. Reactive functions created inside function components are automatically cleared when the component unmounts.\n\n```js\nimport { store, autoEffect, clearEffect } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' })\n\nconst effect = autoEffect(() => document.title = user.name)\nclearEffect(effect)\n```\n\n## Examples with live demos :tv:\n\n#### Beginner\n\n- [Clock Widget](https://risingstack.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/clock)) ([react-native source](/examples/native-clock/)) ([react-native sandbox](https://snack.expo.io/@git/github.com/RisingStack/react-easy-state:examples/native-clock)): a reusable clock widget with a tiny local state store.\n- [Stopwatch](https://risingstack.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/stop-watch)) ([tutorial](https://hackernoon.com/introducing-react-easy-state-1210a156fa16)): a stopwatch with a mix of normal and getter state properties.\n\n#### Advanced\n\n- [Pokédex](https://risingstack.github.io/react-easy-state/examples/pokedex/build) ([source](/examples/pokedex/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/pokedex)): a Pokédex app build with Apollo GraphQL, async actions and a global state.\n- [TodoMVC](https://risingstack.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/todo-mvc)): a classic TodoMVC implementation with a lot of getters/setters and implicit reactivity.\n- [Contacts Table](https://risingstack.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n- [Beer Finder](https://risingstack.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/beer-finder)) ([tutorial](https://medium.com/@solkimicreb/design-patterns-with-react-easy-state-830b927acc7c)): an app with async actions and a mix of local and global state, which finds matching beers for your meal.\n\n## Articles :loudspeaker:\n\n- [Introducing React Easy State](https://blog.risingstack.com/introducing-react-easy-state/): making a simple stopwatch.\n- [Stress Testing React Easy State](https://medium.com/@solkimicreb/stress-testing-react-easy-state-ac321fa3becf): demonstrating Easy State's reactivity with increasingly exotic state mutations.\n- [Design Patterns with React Easy State](https://medium.com/@solkimicreb/design-patterns-with-react-easy-state-830b927acc7c): demonstrating async actions and local and global state management through a beer finder app.\n- [The Ideas Behind React Easy State](https://medium.com/dailyjs/the-ideas-behind-react-easy-state-901d70e4d03e): a deep dive under the hood of Easy State.\n\n## Performance :rocket:\n\nYou can compare Easy State with plain React and other state management libraries with the below benchmarks. It performs a bit better than MobX and similarly to Redux.\n\n- [js-framework-benchmark](https://github.com/krausest/js-framework-benchmark) ([source](https://github.com/krausest/js-framework-benchmark/tree/master/react-v16.1.0-easy-state-v4.0.1-keyed)) ([results](https://rawgit.com/krausest/js-framework-benchmark/master/webdriver-ts-results/table.html))\n\n## Platform support :computer:\n\n- Node: 6 and above\n- Chrome: 49 and above\n- Firefox: 38 and above\n- Safari: 10 and above\n- Edge: 12 and above\n- Opera: 36 and above\n- React Native: 0.59 and above\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n## Alternative builds :wrench:\n\nThis library detects if you use ES6 or commonJS modules and serve the right format to you. The default bundles use ES6 features, which may not yet be supported by some minifier tools. If you experience issues during the build process, you can switch to one of the ES5 builds from below.\n\n- `@risingstack/react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n- `@risingstack/react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n- `@risingstack/react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n- `@risingstack/react-easy-state/dist/cjs.es5.js` exposes an ES5 build with commonJS modules.\n\nIf you use a bundler, set up an alias for `@risingstack/react-easy-state` to point to your desired build. You can learn how to do it with webpack [here](https://webpack.js.org/configuration/resolve/#resolve-alias) and with rollup [here](https://github.com/rollup/rollup-plugin-alias#usage).\n\n## Contributors :sparkles:\n\nContributions are always welcome, please read our [contributing documentation](CONTRIBUTING.md).\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tr>\n    <td align=\"center\"><a href=\"https://bertalan-miklos.now.sh/\"><img src=\"https://avatars3.githubusercontent.com/u/6956014?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Miklos Bertalan</b></sub></a><br /><a href=\"https://github.com/RisingStack/react-easy-state/commits?author=solkimicreb\" title=\"Code\">💻</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=solkimicreb\" title=\"Tests\">⚠️</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=solkimicreb\" title=\"Documentation\">📖</a> <a href=\"#blog-solkimicreb\" title=\"Blogposts\">📝</a></td>\n    <td align=\"center\"><a href=\"https://github.com/rolandszoke\"><img src=\"https://avatars3.githubusercontent.com/u/14181908?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Roland</b></sub></a><br /><a href=\"https://github.com/RisingStack/react-easy-state/commits?author=rolandszoke\" title=\"Code\">💻</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=rolandszoke\" title=\"Tests\">⚠️</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=rolandszoke\" title=\"Documentation\">📖</a></td>\n    <td align=\"center\"><a href=\"https://github.com/danielgrgly\"><img src=\"https://avatars3.githubusercontent.com/u/22714514?s=460&u=cbbc2326d5f671693a1f33671d9eadad902d5191&v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Daniel Gergely</b></sub></a><br /><a href=\"https://github.com/RisingStack/react-easy-state/commits?author=danielgrgly\" title=\"Code\">💻</a> <a href=\"#design-danielgrgly\" title=\"Design\">🎨</a> <a href=\"#example-danielgrgly\" title=\"Examples\">💡</a></td>\n    <td align=\"center\"><a href=\"https://github.com/peteyycz\"><img src=\"https://avatars1.githubusercontent.com/u/7130689?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Peter Czibik</b></sub></a><br /><a href=\"#infra-peteyycz\" title=\"Infrastructure (Hosting, Build-Tools, etc)\">🚇</a></td>\n  </tr>\n</table>\n\n<!-- markdownlint-enable -->\n<!-- prettier-ignore-end -->\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n","readmeFilename":"README.md","gitHead":"0dd021a13b060e2ae932ed5c4de9af1ba7bad2c3","_id":"@risingstack/react-easy-state@6.4.0-alpha.1","_nodeVersion":"12.16.2","_npmVersion":"6.14.4","dist":{"integrity":"sha512-LJRFRmSHlCmXHzpzWP9QvCYcH4WtmyRZzi1Erkos4twDGA+TA4ANwmKI9zTvDkG/M3p8VVypG4F1wwdiAJgZvw==","shasum":"ac465734c18e6c449bbe36788aed9a9584e3d5b9","tarball":"https://registry.npmjs.org/@risingstack/react-easy-state/-/react-easy-state-6.4.0-alpha.1.tgz","fileCount":16,"unpackedSize":188206,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJepXqlCRA9TVsSAnZWagAAVrgQAJ0FZ2e9hym57Jwf1R8/\n+zID64jXniUzHiX5CQqVFtzyoN27Xy4kR7reBmORhl5THADr1NvA7VQB0ZdY\nNmpKlHRPP6itvJlXnWJFuwtw/l7MR/u56C2qAA1THlfGUXnbaRSGGTDV1qjS\nnepuksqb1MaIZGW7AYQzA7zyHcKWLy3utvBL89Sb0CK7DkbloetspOS6nQre\n6RZYpQfwlbLbnxuowGhi/b5+Zt115QZijyOsjoKfHpf/qRZ4WN5GH299Ix/G\n6zVZeO9ck/uBYCS4DyTovx+4fLVo5K74el+dPLu5sxR4K04sraBo3eAQhi8x\naWYlO0UxX+wWgqs6b/x/ea7hNR9U4Zrxn8H4f5HHcKl1Txr9Li3J7d8yOKVJ\nbHmfeFUeiml3TH7vMz3XjpqMxjOeOdAWU6naOOEB8lzAKhEC6q/VBy5APLQc\nYYO8cu/18wva66MMni2TiitCpTFfmVNytNWv8zFoSZLPFx1MtWSskGylia5V\nZi7vQzKEpUQ7hbPkHgOgEUbON/BJcxQxXolzApc3fYEDxBorLJPGHWf8hFuG\nVknN560NgyAuUd6YidGNQfsHDQlVqDhQyfba0dN1v+SKCX2EgWtiW1HVyFLl\n36tEAFNpp3F4RbhJxy5ZnsM7RIADoK+Kt9x4olEiCYBixFV+QlhTycL+WX4S\nGCmS\r\n=g2yy\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDkr4eRPgglvSf89Un1T81KRowI243l7BxkGcEGmQ4jSAIgS6wtwkxSo1Op6V7WJT0JhK7CvLsidP2VkFMKO8YHvEE="}]},"maintainers":[{"name":"dandesz198","email":"dandesz198@gmail.com"},{"name":"fwalkwithm","email":"fwalkwithm@gmail.com"},{"name":"gergelyke","email":"mail@nemethgergely.com"},{"name":"hekike","email":"email@martonpeter.com"},{"name":"jota","email":"simonzsoltjota@gmail.com"},{"name":"kubischj","email":"kubischj@windowslive.com"},{"name":"ozonid","email":"david@risingstack.com"},{"name":"paldiana01","email":"diana.pal@risingstack.com"},{"name":"peteyycz","email":"p.czibik@gmail.com"},{"name":"risingnpm","email":"info@risingstack.com"},{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},{"name":"tamas.hodi","email":"tamas.hodi89@gmail.com"}],"_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.4.0-alpha.1_1587903141426_0.6699542717165856"},"_hasShrinkwrap":false},"7.0.0-alpha.1":{"name":"@risingstack/react-easy-state","version":"7.0.0-alpha.1","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/bundle.cjs.js","module":"dist/bundle.js","types":"types/index.d.ts","scripts":{"test-native":"NATIVE=true jest --config ./jest.native.json --silent","test-web":"jest --config ./jest.web.json --silent","test-web-no-hook":"NOHOOK=true jest --config ./jest.no-hook.json --silent","test":"npm run test-web && npm run test-web-no-hook && npm run test-native","example":"node ./scripts/startExample.js","test-node-support":"node ./scripts/testNode.js","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"eslint --max-warnings 0 --ext js,jsx src scripts __tests__ __mocks__","lint-fix":"prettier . --write","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","build":"rollup --config","build-toc":"node ./scripts/buildToc.js","semantic-release":"semantic-release","contributors":"all-contributors generate"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+https://github.com/RisingStack/react-easy-state.git"},"bugs":{"url":"https://github.com/RisingStack/react-easy-state/issues"},"homepage":"https://github.com/RisingStack/react-easy-state#readme","license":"MIT","keywords":["observable","react-component","react","reactjs","reactive","model","frp","functional-reactive-programming","state management","es6 proxy"],"dependencies":{"@nx-js/observer-util":"^4.3.0-alpha.2"},"peerDependencies":{"react":"*"},"devDependencies":{"@babel/core":"^7.9.6","@babel/polyfill":"^7.8.7","@babel/preset-env":"^7.9.6","@babel/preset-react":"^7.9.4","@commitlint/cli":"^8.3.5","@commitlint/config-angular":"^8.3.4","@rollup/plugin-node-resolve":"^8.0.0","@testing-library/jest-dom":"^5.8.0","@testing-library/react":"^10.0.4","@types/react":"^16.9.35","all-contributors-cli":"^6.14.2","babel-eslint":"^10.1.0","classnames":"^2.2.6","coveralls":"^3.1.0","eslint":"^7.0.0","eslint-config-airbnb":"^18.1.0","eslint-config-prettier":"^6.11.0","eslint-plugin-import":"^2.20.2","eslint-plugin-jsx-a11y":"^6.2.3","eslint-plugin-prettier":"^3.1.3","eslint-plugin-react":"^7.20.0","eslint-plugin-react-hooks":"^4.0.2","husky":"^4.2.5","jest":"^26.0.1","markdown-toc":"^1.2.0","moment":"^2.26.0","no-hook-react":"npm:react@16.7.0","no-hook-react-dom":"npm:react-dom@16.7.0","no-hook-react-testing-library":"npm:react-testing-library@5.4.4","nyc":"^15.0.1","prettier":"^2.0.5","pretty-quick":"^2.0.1","react":"^16.13.1","react-dom":"^16.13.1","react-native":"^0.62.2","react-native-testing-library":"^1.14.0","react-router-dom":"^5.2.0","react-test-renderer":"^16.13.1","rollup":"^2.10.5","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.4.0","rollup-plugin-replace":"^2.2.0","semantic-release":"^17.0.7","sinon":"^9.0.2","styled-components":"^5.1.0"},"husky":{"hooks":{"pre-commit":"pretty-quick --staged && npm run lint","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-push":"npm t"}},"engines":{"node":">=6.0.0"},"browserslist":["node >= 6","chrome >= 49","firefox >= 53","safari >= 10","edge >= 18","opera >= 36"],"readme":"<p align=\"center\">\n  <img src=\"images/logo.svg\" width=\"600px\" height=\"auto\" />\n</p>\n\n## React Easy State - by [RisingStack](https://risingstack.com/)\n\n[![Build](https://img.shields.io/circleci/project/github/RisingStack/react-easy-state/master.svg)](https://circleci.com/gh/RisingStack/react-easy-state/tree/master) [![dependencies Status](https://david-dm.org/RisingStack/react-easy-state/status.svg)](https://david-dm.org/RisingStack/react-easy-state) [![Coverage Status](https://coveralls.io/repos/github/RisingStack/react-easy-state/badge.svg?branch=master&service=github)](https://coveralls.io/github/RisingStack/react-easy-state?branch=master) [![Package size](https://img.shields.io/bundlephobia/minzip/@risingstack/react-easy-state.svg)](https://bundlephobia.com/result?p=@risingstack/react-easy-state) [![Version](https://img.shields.io/npm/v/@risingstack/react-easy-state.svg)](https://www.npmjs.com/package/@risingstack/react-easy-state) [![License](https://img.shields.io/npm/l/@risingstack/react-easy-state.svg)](https://www.npmjs.com/package/@risingstack/react-easy-state) <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->\n[![All Contributors](https://img.shields.io/badge/all_contributors-4-blue.svg)](#contributors)\n<!-- ALL-CONTRIBUTORS-BADGE:END -->\n\n<a href=\"#platform-support-computer\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" height=\"auto\" /></a>\n\n**NEWS:** v6.3.0 fixed a nasty bug that could render [zombie children](https://react-redux.js.org/api/hooks#stale-props-and-zombie-children). Please update to this version at least to save yourself some headaches. Thanks!\n\n<details>\n<summary><strong>Table of Contents</strong></summary>\n<!-- Do not edit the Table of Contents, instead regenerate with `npm run build-toc` -->\n\n<!-- toc -->\n\n* [Introduction :wave:](#introduction-wave)\n* [Installation :cd:](#installation-cd)\n* [Everyday Usage :sunglasses:](#everyday-usage-sunglasses)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Advanced Usage :nerd_face:](#advanced-usage-nerd_face)\n  + [Adding side effects](#adding-side-effects)\n* [API Summary :book:](#api-summary-book)\n  + [store(obj)](#storeobj)\n  + [view(Comp)](#viewcomp)\n  + [batch(fn)](#batchfn)\n  + [autoEffect(fn)](#autoeffectfn)\n  + [clearEffect(fn)](#cleareffectfn)\n* [Examples with live demos :tv:](#examples-with-live-demos-tv)\n* [Articles :loudspeaker:](#articles-loudspeaker)\n* [Performance :rocket:](#performance-rocket)\n* [Platform support :computer:](#platform-support-computer)\n* [Contributors :sparkles:](#contributors-sparkles)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction :wave:\n\nReact Easy State is a practical state management library with two functions and two accompanying rules.\n\n1.  Always wrap your components with `view()`.\n2.  Always wrap your state store objects with `store()`.\n\n```jsx\nimport React from 'react';\nimport { store, view } from '@risingstack/react-easy-state';\n\nconst counter = store({\n  num: 0,\n  increment: () => counter.num++\n});\n\nexport default view(() => (\n  <button onClick={counter.increment}>{counter.num}</button>\n));\n```\n\nThis is enough for it to automatically update your views when needed. It doesn't matter how you structure or mutate your state stores, any syntactically valid code works.\n\nCheck this [TodoMVC codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/todo-mvc?module=%2Fsrc%2FtodosStore.js) or [raw code](/examples/todo-mvc/src/todosStore.js) for a more exciting example with nested data, arrays and getter properties.\n\n## Installation :cd:\n\n`npm install @risingstack/react-easy-state`\n\n<details>\n<summary><strong>Setting up a quick project</strong></summary>\n<p></p>\n\nEasy State supports <a href=\"https://github.com/facebookincubator/create-react-app\">Create React App</a> without additional configuration. Just run the following commands to get started.\n\n```sh\nnpx create-react-app my-app\ncd my-app\nnpm install @risingstack/react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Everyday Usage :sunglasses:\n\n### Creating global stores\n\n`store` creates a state store from the passed object and returns it. A state store behaves just like the passed object. (To be precise, it is a transparent reactive proxy of the original object.)\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Rick' });\n// stores behave like normal JS objects\nuser.name = 'Bob';\n```\n\n<details>\n<summary>State stores may have arbitrary structure and they may be mutated in any syntactically valid way.</summary>\n<p></p>\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\n// stores can include any valid JS structure\n// including nested data, arrays, Maps, Sets, getters, setters, inheritance, ...\nconst user = store({\n  profile: {\n    firstName: 'Bob',\n    lastName: 'Smith',\n    get name() {\n      return `${user.profile.firstName} ${user.profile.lastName}`;\n    },\n  },\n  hobbies: ['programming', 'sports'],\n  friends: new Map(),\n});\n\n// stores may be mutated in any syntactically valid way\nuser.profile.firstName = 'Bob';\ndelete user.profile.lastName;\nuser.hobbies.push('reading');\nuser.friends.set('id', otherUser);\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Async operations can be expressed with the standard async/await syntax.</summary>\n<p></p>\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst userStore = store({\n  user: {},\n  async fetchUser() {\n    userStore.user = await fetch('/user');\n  },\n});\n\nexport default userStore;\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>State stores may import and use other state stores in their methods.</summary>\n<p></p>\n\n_userStore.js_\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst userStore = store({\n  user: {},\n  async fetchUser() {\n    userStore.user = await fetch('/user');\n  },\n});\n\nexport default userStore;\n```\n\n_recipesStore.js_\n\n```js\nimport { store } from '@risingstack/react-easy-state';\nimport userStore from './userStore';\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(\n      `/recipes?user=${userStore.user.id}`,\n    );\n  },\n});\n\nexport default recipesStore;\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Wrap your state stores with <code>store</code> as early as possible.</summary>\n<p></p>\n\n```js\n// DON'T DO THIS\nconst person = { name: 'Bob' };\nperson.name = 'Ann';\n\nexport default store(person);\n```\n\n```js\n// DO THIS INSTEAD\nconst person = store({ name: 'Bob' });\nperson.name = 'Ann';\n\nexport default person;\n```\n\nThe first example wouldn't trigger re-renders on the `person.name = 'Ann'` mutation, because it is targeted at the raw object. Mutating the raw - none `store`-wrapped object - won't schedule renders.\n\n</details>\n<p></p>\n\n<details>\n<summary>Avoid using the <code>this</code> keyword in the methods of your state stores.</summary>\n<p></p>\n\n```jsx\nimport { store, view } from '@risingstack/react-easy-state';\n\nconst counter = store({\n  num: 0,\n  increment() {\n    // DON'T DO THIS\n    this.num++;\n    // DO THIS INSTEAD\n    counter.num++;\n  },\n});\n\nexport default view(() => (\n  <div onClick={counter.increment}>{counter.num}</div>\n));\n```\n\n`this.num++` won't work, because `increment` is passed as a callback and loses its `this`. You should use the direct object reference - `counter` - instead of `this`.\n\n</details>\n\n### Creating reactive views\n\nWrapping your components with `view` turns them into reactive views. A reactive view re-renders whenever a piece of store - used inside its render - changes.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\n// this is a global state store\nconst user = store({ name: 'Bob' });\n\n// this is re-rendered whenever user.name changes\nexport default view(() => (\n  <div>\n    <input\n      value={user.name}\n      onChange={ev => (user.name = ev.target.value)}\n    />\n    <div>Hello {user.name}!</div>\n  </div>\n));\n```\n\n<details>\n<summary><strong>Wrap ALL of your components with <code>view</code> - including class and function ones - even if they don't seem to directly use a store.</strong></summary>\n<p></p>\n\nEvery component that is using a store or part of a store inside its render must be wrapped with `view`. Sometimes store usage is not so explicit and easy to to miss.\n\n```jsx\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst appStore = store({\n  user: { name: 'Ann' },\n});\n\nconst App = view(() => (\n  <div>\n    <h1>My App</h1>\n    <Profile user={appStore.user} />\n  </div>\n));\n\n// DO THIS\nconst Profile = view(({ user }) => <p>Name: {user.name}</p>);\n\n// DON'T DO THIS\n// This won't re-render on appStore.user.name = 'newName' like mutations\nconst Profile = ({ user }) => <p>Name: {user.name}</p>;\n```\n\nIf you are **100% sure** that your component is not using any stores you can skip the `view` wrapper.\n\n```jsx\nimport React from 'react';\n\n// you don't have to wrap this component with `view`\nexport default (() => <p>This is just plain text</p>);\n```\n\n`view` wrapping is advised even in these cases though.\n\n- It saves you from future headaches as your project grows and you start to use stores inside these components.\n- `view` is pretty much equivalent to `memo` if you don't use any stores. That is nearly always nice to have.\n\n</details>\n<p></p>\n\n<details>\n<summary>A single reactive component may use multiple stores inside its render.</summary>\n<p></p>\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' });\nconst timeline = store({ posts: ['react-easy-state'] });\n\n// this is re-rendered whenever user.name or timeline.posts[0] changes\nexport default view(() => (\n  <div>\n    <div>Hello {user.name}!</div>\n    <div>Your first post is: {timeline.posts[0]}</div>\n  </div>\n));\n```\n\n</details>\n<p></p>\n\n<details>\n<summary><code>view</code> implements an optimal <code>shouldComponentUpdate</code> (or <code>memo</code>) for your components.</summary>\n<p></p>\n\n- Using `PureComponent` or `memo` will provide no additional performance benefits.\n\n- Defining a custom `shouldComponentUpdate` may rarely provide performance benefits when you apply some use case specific heuristics inside it.\n\n</details>\n<p></p>\n\n<details>\n<summary>Reactive renders are batched. Multiple synchronous store mutations won't result in multiple re-renders of the same component.</summary>\n<p></p>\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob', age: 30 });\n\nfunction mutateUser() {\n  user.name = 'Ann';\n  user.age = 32;\n}\n\n// calling `mutateUser` will only trigger a single re-render of the below component\n// even though it mutates the store two times in quick succession\nexport default view(() => (\n  <div onClick={mutateUser}>\n    name: {user.name}, age: {user.age}\n  </div>\n));\n```\n\nIf you mutate your stores multiple times synchronously from **exotic task sources**, multiple renders may rarely happen. If you experience performance issues you can batch changes manually with the `batch` function. `batch(fn)` executes the passed function immediately and batches any subsequent re-renders until the function execution finishes.\n\n```jsx\nimport React from 'react';\nimport { view, store, batch } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob', age: 30 });\n\nfunction mutateUser() {\n  // this makes sure the state changes will cause maximum one re-render,\n  // no matter where this function is getting invoked from\n  batch(() => {\n    user.name = 'Ann';\n    user.age = 32;\n  });\n}\n\nexport default view(() => (\n  <div>\n    name: {user.name}, age: {user.age}\n  </div>\n));\n```\n\n> **NOTE:** The React team plans to improve render batching in the future. The `batch` function and built-in batching may be deprecated and removed in the future in favor of React's own batching.\n\n</details>\n<p></p>\n\n<details>\n<summary>Always apply <code>view</code> as the latest (innermost) wrapper when you combine it with other Higher Order Components.</summary>\n<p></p>\n\n```jsx\nimport { view } from '@risingstack/react-easy-state';\nimport { withRouter } from 'react-router-dom';\nimport { withTheme } from 'styled-components';\n\nconst Comp = () => <div>A reactive component</div>;\n\n// DO THIS\nwithRouter(view(Comp));\nwithTheme(view(Comp));\n\n// DON'T DO THIS\nview(withRouter(Comp));\nview(withTheme(Comp));\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Usage with (pre v4.4) React Router.</summary>\n<p></p>\n\n- If routing is not updated properly, wrap your `view(Comp)` - with the `Route`s inside - in `withRouter(view(Comp))`. This lets react-router know when to update.\n\n- The order of the HOCs matter, always use `withRouter(view(Comp))`.\n\nThis is not necessary if you use React Router 4.4+. You can find more details and some reasoning about this in [this react-router docs page](https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md).\n\n</details>\n<p></p>\n\n<details>\n<summary>Usage with React Developer Tools.</summary>\n<p></p>\n\nIf you want React Developer Tools to recognize your reactive view components' names, you have to pass either a **named function** or an anonymous function with **name inference** to the `view` wrapper.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({\n  name: 'Rick',\n});\n\nconst componentName = () => (\n  <div>{user.name}</div>\n);\n\nexport default view(componentName);\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Passing nested data to third party components.</summary>\n<p></p>\n\nThird party helpers - like data grids - may consist of many internal components which can not be wrapped by `view`, but sometimes you would like them to re-render when the passed data mutates. Traditional React components re-render when their props change by reference, so mutating the passed reactive data won't work in these cases. You can solve this issue by deep cloning the observable data before passing it to the component. This creates a new reference for the consuming component on every store mutation.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\nimport Table from 'rc-table';\nimport cloneDeep from 'lodash/cloneDeep';\n\nconst dataStore = store({\n  items: [\n    {\n      product: 'Car',\n      value: 12,\n    },\n  ],\n});\n\nexport default view(() => (\n  <Table data={cloneDeep(dataStore.items)} />\n));\n```\n\n</details>\n\n### Creating local stores\n\nA singleton global store is perfect for something like the current user, but sometimes having local component states is a better fit. Just create a store inside a function component or as a class component property in these cases.\n\n#### Local stores in function components\n\n```jsx\nimport React from 'react'\nimport { view, store } from '@risingstack/react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  const increment = () => counter.num++\n  return <button={increment}>{counter.num}</button>\n})\n```\n\n**Local stores in functions rely on React hooks. They require React and React DOM v16.8+ or React Native v0.59+ to work.**\n\n<details>\n<summary>You can use React hooks - including <code>useState</code> - in function components, Easy State won't interfere with them. Consider using <a href=\"#local-auto-effects-in-function-components\">autoEffect</a> instead of the <code>useEffect</code> hook for the best experience though.</summary>\n<p></p>\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nexport default view(() => {\n  const [name, setName] = useState('Ann');\n  const user = store({ age: 30 });\n  return (\n    <div>\n      <input value={name} onChange={ev => setName(ev.target.value)} />\n      <input\n        value={user.age}\n        onChange={ev => (user.age = ev.target.value)}\n      />\n    </div>\n  );\n});\n```\n\n</details>\n\n#### Local stores in class components\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass Counter extends Component {\n  counter = store({ num: 0 });\n  increment = () => counter.num++;\n\n  render() {\n    return (\n      <button onClick={this.increment}>{this.counter.num}</button>\n    );\n  }\n}\n\nexport default view(Counter);\n```\n\n<details>\n<summary>You can also use vanilla <code>setState</code> in your class components, Easy State won't interfere with it.</summary>\n<p></p>\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass Profile extends Component {\n  state = { name: 'Ann' };\n  user = store({ age: 30 });\n\n  setName = ev => this.setState({ name: ev.target.value });\n  setAge = ev => (this.user.age = ev.target.value);\n\n  render() {\n    return (\n      <div>\n        <input value={this.state.name} onChange={this.setName} />\n        <input value={this.user.age} onChange={this.setAge} />\n      </div>\n    );\n  }\n}\n\nexport default view(Profile);\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Don't name local stores as <code>state</code>. It may conflict with linter rules, which guard against direct state mutations.</summary>\n<p></p>\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass Profile extends Component {\n  // DON'T DO THIS\n  state = store({});\n  // DO THIS\n  user = store({});\n  render() {}\n}\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Deriving local stores from props (<code>getDerivedStateFromProps</code>).</summary>\n<p></p>\n\nClass components wrapped with `view` have an extra static `deriveStoresFromProps` lifecycle method, which works similarly to the vanilla `getDerivedStateFromProps`.\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass NameCard extends Component {\n  userStore = store({ name: 'Bob' });\n\n  static deriveStoresFromProps(props, userStore) {\n    userStore.name = props.name || userStore.name;\n  }\n\n  render() {\n    return <div>{this.userStore.name}</div>;\n  }\n}\n\nexport default view(NameCard);\n```\n\nInstead of returning an object, you should directly mutate the received stores. If you have multiple local stores on a single component, they are all passed as arguments - in their definition order - after the first props argument.\n\n</details>\n\n## Advanced Usage :nerd_face:\n\n### Adding side effects\n\nUse `autoEffect` to react with automatic side effect to your store changes. Auto effects should contain end-of-chain logic - like changing the document title or saving data to LocalStorage. `view` is a special auto effect that does rendering.\n\n<details>\n<summary>Never use auto effects to derive data from other data. Use dynamic getters instead.</summary>\n<p></p>\n\n```jsx\nimport { store, autoEffect } from '@risingstack/react-easy-state';\n\n// DON'T DO THIS\nconst store1 = store({ name: 'Store 1' })\nconst store2 = store({ name: 'Store 2' })\nautoEffect(() => store2.name = store1.name)\n\n// DO THIS INSTEAD\nconst store1 = store({ name: 'Store 1' })\nconst store2 = store({ get name () { return store1.name } })\n```\n\n</details>\n<p></p>\n\n#### Global auto effects\n\nGlobal auto effects can be created with `autoEffect` and cleared up with `clearEffect`.\n\n```jsx\nimport { store, autoEffect, clearEffect } from '@risingstack/react-easy-state';\n\nconst app = store({ name: 'My App' })\nconst effect = autoEffect(() => document.title = app.name)\n\n// this also updates the document title\napp.name = 'My Awesome App'\n\nclearEffect(effect)\n// this won't update the document title, the effect is cleared\napp.name = 'My App'\n```\n\n#### Local auto effects in function components\n\nUse local auto effects in function components instead of the `useEffect` hook when reactive stores are used inside them. These local effects are automatically cleared when the component unmounts.\n\n```jsx\nimport React from 'react'\nimport { store, view, autoEffect } from '@risingstack/react-easy-state';\n\nexport default view(() => {\n  const app = store({ name: 'My App' })\n  // no need to clear the effect\n  autoEffect(() => document.title = app.name)\n})\n```\n\n<details>\n<summary>Explicitly pass none reactive dependencies - like vanillas props and state - to local auto effects in function components.</summary>\n<p></p>\n\nBecause of the design of React hooks you have to explicitly pass all none reactive data to a hook-like dependency array. This makes sure that the effect also runs when the none reactive data changes.\n\n```jsx\nimport React from 'react'\nimport { store, view, autoEffect } from '@risingstack/react-easy-state';\n\nexport default view(({ greeting }) => {\n  const app = store({ name: 'My App' })\n  // pass `greeting` in the dependency array because it is not coming from a store\n  autoEffect(() => document.title = `${greeting} ${app.name}`, [greeting])\n})\n```\n\n</details>\n<p></p>\n\n#### Local auto effects in class components\n\nLocal effects in class components must be cleared when the component unmounts.\n\n```jsx\nimport React, { Component } from 'react'\nimport { store, view, autoEffect } from '@risingstack/react-easy-state';\n\nclass App extends Component {\n  app = store({ name: 'My App' })\n\n  componentDidMount () {\n    this.effect = autoEffect(() => document.title = this.app.name)\n  }\n\n  componentWillUnmount () {\n    // local effects in class components must be cleared on unmount\n    clearEffect(this.effect)\n  }\n}\n```\n\n## API Summary :book:\n\n### store(obj)\n\nCreates an observable store from the passed object and returns it. Can be used outside components for [global stores](#creating-global-stores) and inside components for [local stores]((#creating-local-stores)).\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Rick' });\n```\n\n### view(Comp)\n\nCreates a [reactive view](#creating-reactive-views) from the passed component and returns it. A reactive view re-renders whenever any store data used inside it is mutated.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' });\n\nexport default view(() => (\n  <div>Hello {user.name}!</div>\n));\n```\n\n### batch(fn)\n\nImmediately executes the passed function and batches all store mutations inside it. Batched mutations are guaranteed to not trigger unnecessary double renders. Most task sources are batched automatically, only  use `batch` if you encounter performance issues.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' });\n\nfunction setName() {\n  batch(() => {\n    user.name = 'Rick'\n    user.name = 'Ann'\n  })\n}\n```\n\n### autoEffect(fn)\n\nCreates a reactive function from the passed one, immediately executes it, and returns it. A reactive function automatically re-reruns whenever any store data used inside it is mutated.\n\nCan be used both [outside](#global-auto-effects) and [inside](#local-auto-effects-in-function-components) components.\n\n```js\nimport { store, autoEffect } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' })\n\nautoEffect(() => document.title = user.name)\n```\n\n### clearEffect(fn)\n\nTakes a reactive function (returned by `autoEffect`) and clears the reactivity from it. Cleared reactive functions will no longer re-rerun on related store mutations. Reactive functions created inside function components are automatically cleared when the component unmounts.\n\n```js\nimport { store, autoEffect, clearEffect } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' })\n\nconst effect = autoEffect(() => document.title = user.name)\nclearEffect(effect)\n```\n\n## Examples with live demos :tv:\n\n#### Beginner\n\n- [Clock Widget](https://risingstack.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/clock)) ([react-native source](/examples/native-clock/)) ([react-native sandbox](https://snack.expo.io/@git/github.com/RisingStack/react-easy-state:examples/native-clock)): a reusable clock widget with a tiny local state store.\n- [Stopwatch](https://risingstack.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/stop-watch)) ([tutorial](https://hackernoon.com/introducing-react-easy-state-1210a156fa16)): a stopwatch with a mix of normal and getter state properties.\n\n#### Advanced\n\n- [Pokédex](https://risingstack.github.io/react-easy-state/examples/pokedex/build) ([source](/examples/pokedex/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/pokedex)): a Pokédex app build with Apollo GraphQL, async actions and a global state.\n- [TodoMVC](https://risingstack.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/todo-mvc)): a classic TodoMVC implementation with a lot of getters/setters and implicit reactivity.\n- [Contacts Table](https://risingstack.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n- [Beer Finder](https://risingstack.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/beer-finder)) ([tutorial](https://medium.com/@solkimicreb/design-patterns-with-react-easy-state-830b927acc7c)): an app with async actions and a mix of local and global state, which finds matching beers for your meal.\n\n## Articles :loudspeaker:\n\n- [Introducing React Easy State](https://blog.risingstack.com/introducing-react-easy-state/): making a simple stopwatch.\n- [Stress Testing React Easy State](https://medium.com/@solkimicreb/stress-testing-react-easy-state-ac321fa3becf): demonstrating Easy State's reactivity with increasingly exotic state mutations.\n- [Design Patterns with React Easy State](https://medium.com/@solkimicreb/design-patterns-with-react-easy-state-830b927acc7c): demonstrating async actions and local and global state management through a beer finder app.\n- [The Ideas Behind React Easy State](https://medium.com/dailyjs/the-ideas-behind-react-easy-state-901d70e4d03e): a deep dive under the hood of Easy State.\n\n## Performance :rocket:\n\nYou can compare Easy State with plain React and other state management libraries with the below benchmarks. It performs a bit better than MobX and similarly to Redux.\n\n- [js-framework-benchmark](https://github.com/krausest/js-framework-benchmark) ([source](https://github.com/krausest/js-framework-benchmark/tree/master/react-v16.1.0-easy-state-v4.0.1-keyed)) ([results](https://rawgit.com/krausest/js-framework-benchmark/master/webdriver-ts-results/table.html))\n\n## Platform support :computer:\n\n- Node: 6 and above\n- Chrome: 49 and above\n- Firefox: 38 and above\n- Safari: 10 and above\n- Edge: 12 and above\n- Opera: 36 and above\n- React Native: 0.59 and above\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n## Contributors :sparkles:\n\nContributions are always welcome, please read our [contributing documentation](CONTRIBUTING.md).\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tr>\n    <td align=\"center\"><a href=\"https://bertalan-miklos.now.sh/\"><img src=\"https://avatars3.githubusercontent.com/u/6956014?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Miklos Bertalan</b></sub></a><br /><a href=\"https://github.com/RisingStack/react-easy-state/commits?author=solkimicreb\" title=\"Code\">💻</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=solkimicreb\" title=\"Tests\">⚠️</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=solkimicreb\" title=\"Documentation\">📖</a> <a href=\"#blog-solkimicreb\" title=\"Blogposts\">📝</a></td>\n    <td align=\"center\"><a href=\"https://github.com/rolandszoke\"><img src=\"https://avatars3.githubusercontent.com/u/14181908?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Roland</b></sub></a><br /><a href=\"https://github.com/RisingStack/react-easy-state/commits?author=rolandszoke\" title=\"Code\">💻</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=rolandszoke\" title=\"Tests\">⚠️</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=rolandszoke\" title=\"Documentation\">📖</a></td>\n    <td align=\"center\"><a href=\"https://github.com/danielgrgly\"><img src=\"https://avatars3.githubusercontent.com/u/22714514?s=460&u=cbbc2326d5f671693a1f33671d9eadad902d5191&v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Daniel Gergely</b></sub></a><br /><a href=\"https://github.com/RisingStack/react-easy-state/commits?author=danielgrgly\" title=\"Code\">💻</a> <a href=\"#design-danielgrgly\" title=\"Design\">🎨</a> <a href=\"#example-danielgrgly\" title=\"Examples\">💡</a></td>\n    <td align=\"center\"><a href=\"https://github.com/peteyycz\"><img src=\"https://avatars1.githubusercontent.com/u/7130689?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Peter Czibik</b></sub></a><br /><a href=\"#infra-peteyycz\" title=\"Infrastructure (Hosting, Build-Tools, etc)\">🚇</a></td>\n  </tr>\n</table>\n\n<!-- markdownlint-enable -->\n<!-- prettier-ignore-end -->\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n","readmeFilename":"README.md","gitHead":"ea577e2926bed36ba0989a8f4ccf24722546afca","_id":"@risingstack/react-easy-state@7.0.0-alpha.1","_nodeVersion":"12.16.3","_npmVersion":"6.14.5","dist":{"integrity":"sha512-OWw9pewN1HEpkYvYRWvHvwRo+cd0yMonGD5Z3XuKp2iOJamfYt1LyGaCMOKGbIZLMuhkdbip/FWQymI3bT1F2Q==","shasum":"f5bd948775f33b70d9930a86c0279148de79f1e2","tarball":"https://registry.npmjs.org/@risingstack/react-easy-state/-/react-easy-state-7.0.0-alpha.1.tgz","fileCount":12,"unpackedSize":108809,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJexl//CRA9TVsSAnZWagAAMacP/2J2mYINvbfwiD9Jxg7P\nqqtiwODZUjFem2AQDHiO9Oq8+ny79hytGU2n3FLQEApp8YKfIARufW7iNUaX\nd7CymfUC8RSr6I2llEW7gASAeKaZal1D6pJL3WIIhRLOe2kOS+seSlSfRBTq\nydOpkFEEUBGS7nH2wPhp39VgMTWPFJYgO4aCVAW5j9lGcn1MHSt5GUwauWHY\n+jQ673ZDOmwJiqB5YRG6Pjx1EgHPALLiuL98Ok1/cgYe8hAij/o2gpRhiLAs\nXZzHgoVFxLGcYWSGaLJz/IG0xYUnRR2JNKZVhD4xGXvXtVXRwHFDRwPQ7mxF\nCes/47qO4KHH+1FAXCJLYmmDKjbmvwTPYYFQqExXWLZaXcEU37lV+YOY79iN\nrYoEU/V/nE9o/jZBNRWYRsrgaAby0FK2RmJDSRkHXVnKBCtyhpc8U+mRVRHV\neqljbTwIXoeNggrFzLvUVrNIXkRKgs1WpHStRSpFIpyGhIUUB4/9iY96fGmO\nM0YD0jrmNcFmPVgsbAeElZGbyGLjJiR2K89iJgPpI2VSODWH64lnJiN/plHz\n2Mle/9h1WAIgmeKB187Tv25uwSb0mWdvBCkiaZw3awz3yyrRdQqVJCctSktG\nwzndn2Hg1z6+Md5S/8TC4f0QRddFy371boA0c68kHEyZAh7UYIOpmqdgMRNT\nynlx\r\n=oa2v\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAb2KPd+AMjzpNFdBKSlkaFxOeEJiU+rc9t2aTKoWv4qAiEAwXNBnXpk1oDyfkgVIajSqO7gQUu5CTkg6yypSneobBQ="}]},"maintainers":[{"name":"dandesz198","email":"dandesz198@gmail.com"},{"name":"fwalkwithm","email":"fwalkwithm@gmail.com"},{"name":"gergelyke","email":"mail@nemethgergely.com"},{"name":"hekike","email":"email@martonpeter.com"},{"name":"jota","email":"simonzsoltjota@gmail.com"},{"name":"kubischj","email":"kubischj@windowslive.com"},{"name":"ozonid","email":"david@risingstack.com"},{"name":"paldiana01","email":"diana.pal@risingstack.com"},{"name":"peteyycz","email":"p.czibik@gmail.com"},{"name":"risingnpm","email":"info@risingstack.com"},{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},{"name":"tamas.hodi","email":"tamas.hodi89@gmail.com"}],"_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_7.0.0-alpha.1_1590059006936_0.698743767098063"},"_hasShrinkwrap":false},"6.3.1-alpha.1":{"name":"@risingstack/react-easy-state","version":"6.3.1-alpha.1","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es6.js","module":"dist/es.es6.js","types":"types/index.d.ts","scripts":{"test-native":"NATIVE=true jest --config ./jest.native.json --silent","test-web":"jest --config ./jest.web.json --silent","test-web-no-hook":"NOHOOK=true jest --config ./jest.no-hook.json --silent","test":"npm run test-web && npm run test-web-no-hook && npm run test-native","example":"node ./scripts/startExample.js","test-node-support":"node ./scripts/testNode.js","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"eslint --max-warnings 0 --ext js,jsx src scripts __tests__ __mocks__","lint-fix":"eslint --fix --max-warnings 0 --ext js,jsx src scripts __tests__ __mocks__","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","build":"rollup --config","build-toc":"node ./scripts/buildToc.js","semantic-release":"semantic-release","contributors":"all-contributors generate"},"husky":{"hooks":{"pre-commit":"npm run lint","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-push":"npm t"}},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+https://github.com/RisingStack/react-easy-state.git"},"bugs":{"url":"https://github.com/RisingStack/react-easy-state/issues"},"homepage":"https://github.com/RisingStack/react-easy-state#readme","license":"MIT","keywords":["observable","react-component","react","reactjs","reactive","model","frp","functional-reactive-programming","state management","es6 proxy"],"dependencies":{"@nx-js/observer-util":"^4.2.2"},"peerDependencies":{"react":"*"},"devDependencies":{"@babel/core":"^7.12.10","@babel/plugin-proposal-class-properties":"^7.12.1","@babel/plugin-proposal-export-default-from":"^7.12.1","@babel/plugin-proposal-object-rest-spread":"^7.12.1","@babel/plugin-transform-async-to-generator":"^7.12.1","@babel/plugin-transform-modules-commonjs":"^7.12.1","@babel/polyfill":"^7.8.7","@babel/preset-env":"^7.12.11","@babel/preset-react":"^7.12.10","@babel/compat-data":"^7.12.7","@commitlint/cli":"^11.0.0","@commitlint/config-angular":"^11.0.0","@rollup/plugin-node-resolve":"^11.1.0","@testing-library/jest-dom":"^5.11.9","@testing-library/react":"^11.2.3","@types/react":"^17.0.0","all-contributors-cli":"^6.19.0","babel-eslint":"^10.1.0","classnames":"^2.2.6","coveralls":"^3.1.0","eslint":"^7.18.0","eslint-config-airbnb":"^18.2.1","eslint-config-prettier":"^7.2.0","eslint-plugin-import":"^2.22.1","eslint-plugin-jsx-a11y":"^6.4.1","eslint-plugin-prettier":"^3.3.1","eslint-plugin-react":"^7.22.0","eslint-plugin-react-hooks":"^4.2.0","husky":"^4.3.8","jest":"^26.6.3","markdown-toc":"^1.2.0","moment":"^2.29.1","no-hook-react":"npm:react@16.7.0","no-hook-react-dom":"npm:react-dom@16.7.0","no-hook-react-testing-library":"npm:react-testing-library@5.4.4","nyc":"^15.1.0","prettier":"^2.2.1","react":"^17.0.1","react-dom":"^17.0.1","react-native":"^0.63.4","react-router-dom":"^5.2.0","react-test-renderer":"^17.0.1","rollup":"^2.38.0","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.4.0","rollup-plugin-replace":"^2.2.0","semantic-release":"^17.3.7","sinon":"^9.2.4","styled-components":"^5.2.1"},"engines":{"node":">=6.0.0"},"readme":"<p align=\"center\">\n  <img src=\"images/logo.svg\" width=\"600px\" height=\"auto\" />\n</p>\n\n## React Easy State - by [RisingStack](https://risingstack.com/)\n\n[![Build](https://img.shields.io/circleci/project/github/RisingStack/react-easy-state/master.svg)](https://circleci.com/gh/RisingStack/react-easy-state/tree/master) [![dependencies Status](https://david-dm.org/RisingStack/react-easy-state/status.svg)](https://david-dm.org/RisingStack/react-easy-state) [![Coverage Status](https://coveralls.io/repos/github/RisingStack/react-easy-state/badge.svg?branch=master&service=github)](https://coveralls.io/github/RisingStack/react-easy-state?branch=master) [![Package size](https://img.shields.io/bundlephobia/minzip/@risingstack/react-easy-state.svg)](https://bundlephobia.com/result?p=@risingstack/react-easy-state) [![Version](https://img.shields.io/npm/v/@risingstack/react-easy-state.svg)](https://www.npmjs.com/package/@risingstack/react-easy-state) [![License](https://img.shields.io/npm/l/@risingstack/react-easy-state.svg)](https://www.npmjs.com/package/@risingstack/react-easy-state) <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->\n[![All Contributors](https://img.shields.io/badge/all_contributors-4-blue.svg)](#contributors)\n<!-- ALL-CONTRIBUTORS-BADGE:END -->\n\n<a href=\"#platform-support-computer\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" height=\"auto\" /></a>\n\n**NEWS:** v6.3.0 fixed a nasty bug that could render [zombie children](https://react-redux.js.org/api/hooks#stale-props-and-zombie-children). Please update to this version at least to save yourself some headaches. Thanks!\n\n<details>\n<summary><strong>Table of Contents</strong></summary>\n<!-- Do not edit the Table of Contents, instead regenerate with `npm run build-toc` -->\n\n<!-- toc -->\n\n* [Introduction :wave:](#introduction-wave)\n* [Installation :cd:](#installation-cd)\n* [Everyday Usage :sunglasses:](#everyday-usage-sunglasses)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Advanced Usage :nerd_face:](#advanced-usage-nerd_face)\n  + [Adding side effects](#adding-side-effects)\n* [API Summary :book:](#api-summary-book)\n  + [store(obj)](#storeobj)\n  + [view(Comp)](#viewcomp)\n  + [batch(fn)](#batchfn)\n  + [autoEffect(fn)](#autoeffectfn)\n  + [clearEffect(fn)](#cleareffectfn)\n* [Examples with live demos :tv:](#examples-with-live-demos-tv)\n* [Articles :loudspeaker:](#articles-loudspeaker)\n* [Performance :rocket:](#performance-rocket)\n* [Platform support :computer:](#platform-support-computer)\n* [Alternative builds :wrench:](#alternative-builds-wrench)\n* [Contributors :sparkles:](#contributors-sparkles)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction :wave:\n\nReact Easy State is a practical state management library with two functions and two accompanying rules.\n\n1.  Always wrap your components with `view()`.\n2.  Always wrap your state store objects with `store()`.\n\n```jsx\nimport React from 'react';\nimport { store, view } from '@risingstack/react-easy-state';\n\nconst counter = store({\n  num: 0,\n  increment: () => counter.num++\n});\n\nexport default view(() => (\n  <button onClick={counter.increment}>{counter.num}</button>\n));\n```\n\nThis is enough for it to automatically update your views when needed. It doesn't matter how you structure or mutate your state stores, any syntactically valid code works.\n\nCheck this [TodoMVC codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/todo-mvc?module=%2Fsrc%2FtodosStore.js) or [raw code](/examples/todo-mvc/src/todosStore.js) for a more exciting example with nested data, arrays and getter properties.\n\n## Installation :cd:\n\n`npm install @risingstack/react-easy-state`\n\n<details>\n<summary><strong>Setting up a quick project</strong></summary>\n<p></p>\n\nEasy State supports <a href=\"https://github.com/facebookincubator/create-react-app\">Create React App</a> without additional configuration. Just run the following commands to get started.\n\n```sh\nnpx create-react-app my-app\ncd my-app\nnpm install @risingstack/react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Everyday Usage :sunglasses:\n\n### Creating global stores\n\n`store` creates a state store from the passed object and returns it. A state store behaves just like the passed object. (To be precise, it is a transparent reactive proxy of the original object.)\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Rick' });\n// stores behave like normal JS objects\nuser.name = 'Bob';\n```\n\n<details>\n<summary>State stores may have arbitrary structure and they may be mutated in any syntactically valid way.</summary>\n<p></p>\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\n// stores can include any valid JS structure\n// including nested data, arrays, Maps, Sets, getters, setters, inheritance, ...\nconst user = store({\n  profile: {\n    firstName: 'Bob',\n    lastName: 'Smith',\n    get name() {\n      return `${user.profile.firstName} ${user.profile.lastName}`;\n    },\n  },\n  hobbies: ['programming', 'sports'],\n  friends: new Map(),\n});\n\n// stores may be mutated in any syntactically valid way\nuser.profile.firstName = 'Bob';\ndelete user.profile.lastName;\nuser.hobbies.push('reading');\nuser.friends.set('id', otherUser);\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Async operations can be expressed with the standard async/await syntax.</summary>\n<p></p>\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst userStore = store({\n  user: {},\n  async fetchUser() {\n    userStore.user = await fetch('/user');\n  },\n});\n\nexport default userStore;\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>State stores may import and use other state stores in their methods.</summary>\n<p></p>\n\n_userStore.js_\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst userStore = store({\n  user: {},\n  async fetchUser() {\n    userStore.user = await fetch('/user');\n  },\n});\n\nexport default userStore;\n```\n\n_recipesStore.js_\n\n```js\nimport { store } from '@risingstack/react-easy-state';\nimport userStore from './userStore';\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(\n      `/recipes?user=${userStore.user.id}`,\n    );\n  },\n});\n\nexport default recipesStore;\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Wrap your state stores with <code>store</code> as early as possible.</summary>\n<p></p>\n\n```js\n// DON'T DO THIS\nconst person = { name: 'Bob' };\nperson.name = 'Ann';\n\nexport default store(person);\n```\n\n```js\n// DO THIS INSTEAD\nconst person = store({ name: 'Bob' });\nperson.name = 'Ann';\n\nexport default person;\n```\n\nThe first example wouldn't trigger re-renders on the `person.name = 'Ann'` mutation, because it is targeted at the raw object. Mutating the raw - non-`store`-wrapped object - won't schedule renders.\n\n</details>\n<p></p>\n\n<details>\n<summary>Avoid using the <code>this</code> keyword in the methods of your state stores.</summary>\n<p></p>\n\n```jsx\nimport { store, view } from '@risingstack/react-easy-state';\n\nconst counter = store({\n  num: 0,\n  increment() {\n    // DON'T DO THIS\n    this.num++;\n    // DO THIS INSTEAD\n    counter.num++;\n  },\n});\n\nexport default view(() => (\n  <div onClick={counter.increment}>{counter.num}</div>\n));\n```\n\n`this.num++` won't work, because `increment` is passed as a callback and loses its `this`. You should use the direct object reference - `counter` - instead of `this`.\n\n</details>\n\n### Creating reactive views\n\nWrapping your components with `view` turns them into reactive views. A reactive view re-renders whenever a piece of store - used inside its render - changes.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\n// this is a global state store\nconst user = store({ name: 'Bob' });\n\n// this is re-rendered whenever user.name changes\nexport default view(() => (\n  <div>\n    <input\n      value={user.name}\n      onChange={ev => (user.name = ev.target.value)}\n    />\n    <div>Hello {user.name}!</div>\n  </div>\n));\n```\n\n<details>\n<summary><strong>Wrap ALL of your components with <code>view</code> - including class and function ones - even if they don't seem to directly use a store.</strong></summary>\n<p></p>\n\nEvery component that is using a store or part of a store inside its render must be wrapped with `view`. Sometimes store usage is not so explicit and easy to to miss.\n\n```jsx\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst appStore = store({\n  user: { name: 'Ann' },\n});\n\nconst App = view(() => (\n  <div>\n    <h1>My App</h1>\n    <Profile user={appStore.user} />\n  </div>\n));\n\n// DO THIS\nconst Profile = view(({ user }) => <p>Name: {user.name}</p>);\n\n// DON'T DO THIS\n// This won't re-render on appStore.user.name = 'newName' like mutations\nconst Profile = ({ user }) => <p>Name: {user.name}</p>;\n```\n\nIf you are **100% sure** that your component is not using any stores you can skip the `view` wrapper.\n\n```jsx\nimport React from 'react';\n\n// you don't have to wrap this component with `view`\nexport default (() => <p>This is just plain text</p>);\n```\n\n`view` wrapping is advised even in these cases though.\n\n- It saves you from future headaches as your project grows and you start to use stores inside these components.\n- `view` is pretty much equivalent to `memo` if you don't use any stores. That is nearly always nice to have.\n\n</details>\n<p></p>\n\n<details>\n<summary>A single reactive component may use multiple stores inside its render.</summary>\n<p></p>\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' });\nconst timeline = store({ posts: ['react-easy-state'] });\n\n// this is re-rendered whenever user.name or timeline.posts[0] changes\nexport default view(() => (\n  <div>\n    <div>Hello {user.name}!</div>\n    <div>Your first post is: {timeline.posts[0]}</div>\n  </div>\n));\n```\n\n</details>\n<p></p>\n\n<details>\n<summary><code>view</code> implements an optimal <code>shouldComponentUpdate</code> (or <code>memo</code>) for your components.</summary>\n<p></p>\n\n- Using `PureComponent` or `memo` will provide no additional performance benefits.\n\n- Defining a custom `shouldComponentUpdate` may rarely provide performance benefits when you apply some use case specific heuristics inside it.\n\n</details>\n<p></p>\n\n<details>\n<summary>Reactive renders are batched. Multiple synchronous store mutations won't result in multiple re-renders of the same component.</summary>\n<p></p>\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob', age: 30 });\n\nfunction mutateUser() {\n  user.name = 'Ann';\n  user.age = 32;\n}\n\n// calling `mutateUser` will only trigger a single re-render of the below component\n// even though it mutates the store two times in quick succession\nexport default view(() => (\n  <div onClick={mutateUser}>\n    name: {user.name}, age: {user.age}\n  </div>\n));\n```\n\nIf you mutate your stores multiple times synchronously from **exotic task sources**, multiple renders may rarely happen. If you experience performance issues you can batch changes manually with the `batch` function. `batch(fn)` executes the passed function immediately and batches any subsequent re-renders until the function execution finishes.\n\n```jsx\nimport React from 'react';\nimport { view, store, batch } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob', age: 30 });\n\nfunction mutateUser() {\n  // this makes sure the state changes will cause maximum one re-render,\n  // no matter where this function is getting invoked from\n  batch(() => {\n    user.name = 'Ann';\n    user.age = 32;\n  });\n}\n\nexport default view(() => (\n  <div>\n    name: {user.name}, age: {user.age}\n  </div>\n));\n```\n\n> **NOTE:** The React team plans to improve render batching in the future. The `batch` function and built-in batching may be deprecated and removed in the future in favor of React's own batching.\n\n</details>\n<p></p>\n\n<details>\n<summary>Always apply <code>view</code> as the latest (innermost) wrapper when you combine it with other Higher Order Components.</summary>\n<p></p>\n\n```jsx\nimport { view } from '@risingstack/react-easy-state';\nimport { withRouter } from 'react-router-dom';\nimport { withTheme } from 'styled-components';\n\nconst Comp = () => <div>A reactive component</div>;\n\n// DO THIS\nwithRouter(view(Comp));\nwithTheme(view(Comp));\n\n// DON'T DO THIS\nview(withRouter(Comp));\nview(withTheme(Comp));\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Usage with (pre v4.4) React Router.</summary>\n<p></p>\n\n- If routing is not updated properly, wrap your `view(Comp)` - with the `Route`s inside - in `withRouter(view(Comp))`. This lets react-router know when to update.\n\n- The order of the HOCs matter, always use `withRouter(view(Comp))`.\n\nThis is not necessary if you use React Router 4.4+. You can find more details and some reasoning about this in [this react-router docs page](https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md).\n\n</details>\n<p></p>\n\n<details>\n<summary>Usage with React Developer Tools.</summary>\n<p></p>\n\nIf you want React Developer Tools to recognize your reactive view components' names, you have to pass either a **named function** or an anonymous function with **name inference** to the `view` wrapper.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({\n  name: 'Rick',\n});\n\nconst componentName = () => (\n  <div>{user.name}</div>\n);\n\nexport default view(componentName);\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Passing nested data to third party components.</summary>\n<p></p>\n\nThird party helpers - like data grids - may consist of many internal components which can not be wrapped by `view`, but sometimes you would like them to re-render when the passed data mutates. Traditional React components re-render when their props change by reference, so mutating the passed reactive data won't work in these cases. You can solve this issue by deep cloning the observable data before passing it to the component. This creates a new reference for the consuming component on every store mutation.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\nimport Table from 'rc-table';\nimport cloneDeep from 'lodash/cloneDeep';\n\nconst dataStore = store({\n  items: [\n    {\n      product: 'Car',\n      value: 12,\n    },\n  ],\n});\n\nexport default view(() => (\n  <Table data={cloneDeep(dataStore.items)} />\n));\n```\n\n</details>\n\n### Creating local stores\n\nA singleton global store is perfect for something like the current user, but sometimes having local component states is a better fit. Just create a store inside a function component or as a class component property in these cases.\n\n#### Local stores in function components\n\n```jsx\nimport React from 'react'\nimport { view, store } from '@risingstack/react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  const increment = () => counter.num++\n  return <button={increment}>{counter.num}</button>\n})\n```\n\n**Local stores in functions rely on React hooks. They require React and React DOM v16.8+ or React Native v0.59+ to work.**\n\n<details>\n<summary>You can use React hooks - including <code>useState</code> - in function components, Easy State won't interfere with them. Consider using <a href=\"#local-auto-effects-in-function-components\">autoEffect</a> instead of the <code>useEffect</code> hook for the best experience though.</summary>\n<p></p>\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nexport default view(() => {\n  const [name, setName] = useState('Ann');\n  const user = store({ age: 30 });\n  return (\n    <div>\n      <input value={name} onChange={ev => setName(ev.target.value)} />\n      <input\n        value={user.age}\n        onChange={ev => (user.age = ev.target.value)}\n      />\n    </div>\n  );\n});\n```\n\n</details>\n\n#### Local stores in class components\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass Counter extends Component {\n  counter = store({ num: 0 });\n  increment = () => counter.num++;\n\n  render() {\n    return (\n      <button onClick={this.increment}>{this.counter.num}</button>\n    );\n  }\n}\n\nexport default view(Counter);\n```\n\n<details>\n<summary>You can also use vanilla <code>setState</code> in your class components, Easy State won't interfere with it.</summary>\n<p></p>\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass Profile extends Component {\n  state = { name: 'Ann' };\n  user = store({ age: 30 });\n\n  setName = ev => this.setState({ name: ev.target.value });\n  setAge = ev => (this.user.age = ev.target.value);\n\n  render() {\n    return (\n      <div>\n        <input value={this.state.name} onChange={this.setName} />\n        <input value={this.user.age} onChange={this.setAge} />\n      </div>\n    );\n  }\n}\n\nexport default view(Profile);\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Don't name local stores as <code>state</code>. It may conflict with linter rules, which guard against direct state mutations.</summary>\n<p></p>\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass Profile extends Component {\n  // DON'T DO THIS\n  state = store({});\n  // DO THIS\n  user = store({});\n  render() {}\n}\n```\n\n</details>\n<p></p>\n\n<details>\n<summary>Deriving local stores from props (<code>getDerivedStateFromProps</code>).</summary>\n<p></p>\n\nClass components wrapped with `view` have an extra static `deriveStoresFromProps` lifecycle method, which works similarly to the vanilla `getDerivedStateFromProps`.\n\n```jsx\nimport React, { Component } from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nclass NameCard extends Component {\n  userStore = store({ name: 'Bob' });\n\n  static deriveStoresFromProps(props, userStore) {\n    userStore.name = props.name || userStore.name;\n  }\n\n  render() {\n    return <div>{this.userStore.name}</div>;\n  }\n}\n\nexport default view(NameCard);\n```\n\nInstead of returning an object, you should directly mutate the received stores. If you have multiple local stores on a single component, they are all passed as arguments - in their definition order - after the first props argument.\n\n</details>\n\n## Advanced Usage :nerd_face:\n\n### Adding side effects\n\nUse `autoEffect` to react with automatic side effect to your store changes. Auto effects should contain end-of-chain logic - like changing the document title or saving data to LocalStorage. `view` is a special auto effect that does rendering.\n\n<details>\n<summary>Never use auto effects to derive data from other data. Use dynamic getters instead.</summary>\n<p></p>\n\n```jsx\nimport { store, autoEffect } from '@risingstack/react-easy-state';\n\n// DON'T DO THIS\nconst store1 = store({ name: 'Store 1' })\nconst store2 = store({ name: 'Store 2' })\nautoEffect(() => store2.name = store1.name)\n\n// DO THIS INSTEAD\nconst store1 = store({ name: 'Store 1' })\nconst store2 = store({ get name () { return store1.name } })\n```\n\n</details>\n<p></p>\n\n#### Global auto effects\n\nGlobal auto effects can be created with `autoEffect` and cleared up with `clearEffect`.\n\n```jsx\nimport { store, autoEffect, clearEffect } from '@risingstack/react-easy-state';\n\nconst app = store({ name: 'My App' })\nconst effect = autoEffect(() => document.title = app.name)\n\n// this also updates the document title\napp.name = 'My Awesome App'\n\nclearEffect(effect)\n// this won't update the document title, the effect is cleared\napp.name = 'My App'\n```\n\n#### Local auto effects in function components\n\nUse local auto effects in function components instead of the `useEffect` hook when reactive stores are used inside them. These local effects are automatically cleared when the component unmounts.\n\n```jsx\nimport React from 'react'\nimport { store, view, autoEffect } from '@risingstack/react-easy-state';\n\nexport default view(() => {\n  const app = store({ name: 'My App' })\n  // no need to clear the effect\n  autoEffect(() => document.title = app.name)\n})\n```\n\n<details>\n<summary>Explicitly pass non-reactive dependencies - like vanillas props and state - to local auto effects in function components.</summary>\n<p></p>\n\nBecause of the design of React hooks you have to explicitly pass all non-reactive data to a hook-like dependency array. This makes sure that the effect also runs when the non-reactive data changes.\n\n```jsx\nimport React from 'react'\nimport { store, view, autoEffect } from '@risingstack/react-easy-state';\n\nexport default view(({ greeting }) => {\n  const app = store({ name: 'My App' })\n  // pass `greeting` in the dependency array because it is not coming from a store\n  autoEffect(() => document.title = `${greeting} ${app.name}`, [greeting])\n})\n```\n\n</details>\n<p></p>\n\n#### Local auto effects in class components\n\nLocal effects in class components must be cleared when the component unmounts.\n\n```jsx\nimport React, { Component } from 'react'\nimport { store, view, autoEffect } from '@risingstack/react-easy-state';\n\nclass App extends Component {\n  app = store({ name: 'My App' })\n\n  componentDidMount () {\n    this.effect = autoEffect(() => document.title = this.app.name)\n  }\n\n  componentWillUnmount () {\n    // local effects in class components must be cleared on unmount\n    clearEffect(this.effect)\n  }\n}\n```\n\n## API Summary :book:\n\n### store(obj)\n\nCreates an observable store from the passed object and returns it. Can be used outside components for [global stores](#creating-global-stores) and inside components for [local stores]((#creating-local-stores)).\n\n```js\nimport { store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Rick' });\n```\n\n### view(Comp)\n\nCreates a [reactive view](#creating-reactive-views) from the passed component and returns it. A reactive view re-renders whenever any store data used inside it is mutated.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' });\n\nexport default view(() => (\n  <div>Hello {user.name}!</div>\n));\n```\n\n### batch(fn)\n\nImmediately executes the passed function and batches all store mutations inside it. Batched mutations are guaranteed to not trigger unnecessary double renders. Most task sources are batched automatically, only  use `batch` if you encounter performance issues.\n\n```jsx\nimport React from 'react';\nimport { view, store } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' });\n\nfunction setName() {\n  batch(() => {\n    user.name = 'Rick'\n    user.name = 'Ann'\n  })\n}\n```\n\n### autoEffect(fn)\n\nCreates a reactive function from the passed one, immediately executes it, and returns it. A reactive function automatically re-reruns whenever any store data used inside it is mutated.\n\nCan be used both [outside](#global-auto-effects) and [inside](#local-auto-effects-in-function-components) components.\n\n```js\nimport { store, autoEffect } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' })\n\nautoEffect(() => document.title = user.name)\n```\n\n### clearEffect(fn)\n\nTakes a reactive function (returned by `autoEffect`) and clears the reactivity from it. Cleared reactive functions will no longer re-rerun on related store mutations. Reactive functions created inside function components are automatically cleared when the component unmounts.\n\n```js\nimport { store, autoEffect, clearEffect } from '@risingstack/react-easy-state';\n\nconst user = store({ name: 'Bob' })\n\nconst effect = autoEffect(() => document.title = user.name)\nclearEffect(effect)\n```\n\n## Examples with live demos :tv:\n\n#### Beginner\n\n- [Clock Widget](https://risingstack.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/clock)) ([react-native source](/examples/native-clock/)) ([react-native sandbox](https://snack.expo.io/@git/github.com/RisingStack/react-easy-state:examples/native-clock)): a reusable clock widget with a tiny local state store.\n- [Stopwatch](https://risingstack.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/stop-watch)) ([tutorial](https://hackernoon.com/introducing-react-easy-state-1210a156fa16)): a stopwatch with a mix of normal and getter state properties.\n\n#### Advanced\n\n- [Pokédex](https://risingstack.github.io/react-easy-state/examples/pokedex/build) ([source](/examples/pokedex/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/pokedex)): a Pokédex app build with Apollo GraphQL, async actions and a global state.\n- [TodoMVC](https://risingstack.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/todo-mvc)): a classic TodoMVC implementation with a lot of getters/setters and implicit reactivity.\n- [Contacts Table](https://risingstack.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n- [Beer Finder](https://risingstack.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/RisingStack/react-easy-state/tree/master/examples/beer-finder)) ([tutorial](https://medium.com/@solkimicreb/design-patterns-with-react-easy-state-830b927acc7c)): an app with async actions and a mix of local and global state, which finds matching beers for your meal.\n\n## Articles :loudspeaker:\n\n- [Introducing React Easy State](https://blog.risingstack.com/introducing-react-easy-state/): making a simple stopwatch.\n- [Stress Testing React Easy State](https://medium.com/@solkimicreb/stress-testing-react-easy-state-ac321fa3becf): demonstrating Easy State's reactivity with increasingly exotic state mutations.\n- [Design Patterns with React Easy State](https://medium.com/@solkimicreb/design-patterns-with-react-easy-state-830b927acc7c): demonstrating async actions and local and global state management through a beer finder app.\n- [The Ideas Behind React Easy State](https://medium.com/dailyjs/the-ideas-behind-react-easy-state-901d70e4d03e): a deep dive under the hood of Easy State.\n\n## Performance :rocket:\n\nYou can compare Easy State with plain React and other state management libraries with the below benchmarks. It performs a bit better than MobX and similarly to Redux.\n\n- [js-framework-benchmark](https://github.com/krausest/js-framework-benchmark) ([source](https://github.com/krausest/js-framework-benchmark/tree/master/react-v16.1.0-easy-state-v4.0.1-keyed)) ([results](https://rawgit.com/krausest/js-framework-benchmark/master/webdriver-ts-results/table.html))\n\n## Platform support :computer:\n\n- Node: 6 and above\n- Chrome: 49 and above\n- Firefox: 38 and above\n- Safari: 10 and above\n- Edge: 12 and above\n- Opera: 36 and above\n- React Native: 0.59 and above\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n## Alternative builds :wrench:\n\nThis library detects if you use ES6 or commonJS modules and serve the right format to you. The default bundles use ES6 features, which may not yet be supported by some minifier tools. If you experience issues during the build process, you can switch to one of the ES5 builds from below.\n\n- `@risingstack/react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n- `@risingstack/react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n- `@risingstack/react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n- `@risingstack/react-easy-state/dist/cjs.es5.js` exposes an ES5 build with commonJS modules.\n\nIf you use a bundler, set up an alias for `@risingstack/react-easy-state` to point to your desired build. You can learn how to do it with webpack [here](https://webpack.js.org/configuration/resolve/#resolve-alias) and with rollup [here](https://github.com/rollup/rollup-plugin-alias#usage).\n\n## Contributors :sparkles:\n\nContributions are always welcome, please read our [contributing documentation](CONTRIBUTING.md).\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tr>\n    <td align=\"center\"><a href=\"https://bertalan-miklos.now.sh/\"><img src=\"https://avatars3.githubusercontent.com/u/6956014?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Miklos Bertalan</b></sub></a><br /><a href=\"https://github.com/RisingStack/react-easy-state/commits?author=solkimicreb\" title=\"Code\">💻</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=solkimicreb\" title=\"Tests\">⚠️</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=solkimicreb\" title=\"Documentation\">📖</a> <a href=\"#blog-solkimicreb\" title=\"Blogposts\">📝</a></td>\n    <td align=\"center\"><a href=\"https://github.com/rolandszoke\"><img src=\"https://avatars3.githubusercontent.com/u/14181908?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Roland</b></sub></a><br /><a href=\"https://github.com/RisingStack/react-easy-state/commits?author=rolandszoke\" title=\"Code\">💻</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=rolandszoke\" title=\"Tests\">⚠️</a> <a href=\"https://github.com/RisingStack/react-easy-state/commits?author=rolandszoke\" title=\"Documentation\">📖</a></td>\n    <td align=\"center\"><a href=\"https://github.com/danielgrgly\"><img src=\"https://avatars3.githubusercontent.com/u/22714514?s=460&u=cbbc2326d5f671693a1f33671d9eadad902d5191&v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Daniel Gergely</b></sub></a><br /><a href=\"https://github.com/RisingStack/react-easy-state/commits?author=danielgrgly\" title=\"Code\">💻</a> <a href=\"#design-danielgrgly\" title=\"Design\">🎨</a> <a href=\"#example-danielgrgly\" title=\"Examples\">💡</a></td>\n    <td align=\"center\"><a href=\"https://github.com/peteyycz\"><img src=\"https://avatars1.githubusercontent.com/u/7130689?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Peter Czibik</b></sub></a><br /><a href=\"#infra-peteyycz\" title=\"Infrastructure (Hosting, Build-Tools, etc)\">🚇</a></td>\n  </tr>\n</table>\n\n<!-- markdownlint-enable -->\n<!-- prettier-ignore-end -->\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n","readmeFilename":"README.md","gitHead":"9d3e1a4db84a9b2daf0bc30f60ee06e75015c1a2","_id":"@risingstack/react-easy-state@6.3.1-alpha.1","_nodeVersion":"12.20.1","_npmVersion":"6.14.11","dist":{"integrity":"sha512-re4izW0iw/IR8Ff2PTbMbWhMB7sYuxUbM+C2CmmC7rgV98AZI2UpwSMY8sO8tvSuyWxKEf0J7FD7NVv4XlZuDg==","shasum":"dfc4f76c43bdd738bb03c29550c873db32a3a64c","tarball":"https://registry.npmjs.org/@risingstack/react-easy-state/-/react-easy-state-6.3.1-alpha.1.tgz","fileCount":16,"unpackedSize":201594,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgEtLmCRA9TVsSAnZWagAAZXkP+gJeqsNknWiMPVSJGagD\nsDvzFhz781tC38NzdrnnIMGs6WcdBHzzBa/Gn3J7qNyUnKFzRPqU/0nAJEMK\niwiMBoDn9o9UTQEkYlRqWz6VT/qXs4unPFzMs0qOIRkIIBXu8PAbAGwEkdfC\nh9dVUHqBLqmWl7YbQ6Qpp66f+eqJnvIFNhy1y0vTMfa3HtV6vzENvjpWO+wI\np70n8ulnflWbHjUHLkF8UM8qptFbQvhLac+Fha95+ew3cL6XEiWrgeecySRm\nAkH3u4Zp9q8kj65aoW27B7e6duqEHyeyctezTqjGSc0Vs4E/7k1rE5dB/QkD\nmRpNZ1TvEu+38dzHXHHofRmqqUFv5fDHV9Sv5h1MIBK+S0AP6IG72jZScm40\nMPOhm06reZZFZAiiKfbg2Kw/eaiiqRUW7hOTaDm6gTqUHXK88X/f0oKtS+FZ\nLoAKnIOOa9R8PafdRbHBkv0Gj+Q3Z0plxHXJOY+2/ocuCJyuWrAKKxuzNDZ+\n6nbWohCwYHvV9rOZRPiphJCn/yxi79PgCtcClF3WmmoQ6kGuaRsRWCdZ70Ea\no4Ah+dfUdZvW3wvRn1MNM42wWCwjGPEQxjyaZ4Ir5xXNTyxF28J3PPM/sREp\nYqPquIdqH5PU8gmHXrDIGy6TP04pZtM6XSJGBS4SdXd71dl4FwTClv4nGzWJ\ncjYT\r\n=PGnD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHBHnNhELMmyBZXsOUHhj6RBntCwApSn0H67TPgm7Ki1AiAX7XskliZCsuzxOas7/jYf1E0Ir5hAIg7xB1dypv5eKg=="}]},"_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"directories":{},"maintainers":[{"name":"paldiana01","email":"diana.pal@risingstack.com"},{"name":"risingnpm","email":"info@risingstack.com"},{"name":"gergelyke","email":"mail@nemethgergely.com"},{"name":"hekike","email":"email@martonpeter.com"},{"name":"peteyycz","email":"p.czibik@gmail.com"},{"name":"tamas.hodi","email":"tamas.hodi89@gmail.com"},{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},{"name":"dandesz198","email":"dandesz198@gmail.com"},{"name":"jota","email":"simonzsoltjota@gmail.com"},{"name":"ozonid","email":"david@risingstack.com"},{"name":"fwalkwithm","email":"fwalkwithm@gmail.com"},{"name":"kubischj","email":"kubischj@windowslive.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.3.1-alpha.1_1611846374193_0.0215208034715344"},"_hasShrinkwrap":false}},"time":{"created":"2020-03-11T12:57:21.035Z","6.1.3":"2020-03-11T12:57:21.295Z","modified":"2022-04-06T20:13:03.253Z","6.2.0":"2020-03-30T10:11:58.238Z","0.0.0-experimental-912b2213":"2020-03-31T08:57:59.234Z","6.2.1":"2020-04-08T19:21:10.300Z","6.2.2":"2020-04-14T15:48:45.081Z","6.2.3":"2020-04-14T15:55:08.821Z","6.2.4":"2020-04-19T23:08:13.747Z","6.3.0":"2020-04-24T09:39:26.695Z","6.4.0-alpha.1":"2020-04-26T12:12:21.544Z","7.0.0-alpha.1":"2020-05-21T11:03:27.152Z","6.3.1-alpha.1":"2021-01-28T15:06:14.301Z"},"maintainers":[{"name":"paldiana01","email":"diana.pal@risingstack.com"},{"name":"risingnpm","email":"info@risingstack.com"},{"name":"gergelyke","email":"mail@nemethgergely.com"},{"name":"hekike","email":"email@martonpeter.com"},{"name":"peteyycz","email":"p.czibik@gmail.com"},{"name":"tamas.hodi","email":"tamas.hodi89@gmail.com"},{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},{"name":"dandesz198","email":"dandesz198@gmail.com"},{"name":"jota","email":"simonzsoltjota@gmail.com"},{"name":"ozonid","email":"david@risingstack.com"},{"name":"fwalkwithm","email":"fwalkwithm@gmail.com"},{"name":"kubischj","email":"kubischj@windowslive.com"}],"description":"React state management with a minimal API. Made with ES6 Proxies.","homepage":"https://github.com/RisingStack/react-easy-state#readme","keywords":["observable","react-component","react","reactjs","reactive","model","frp","functional-reactive-programming","state management","es6 proxy"],"repository":{"type":"git","url":"git+https://github.com/RisingStack/react-easy-state.git"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"bugs":{"url":"https://github.com/RisingStack/react-easy-state/issues"},"license":"MIT","readme":"","readmeFilename":""}