{"_id":"react-easy-state","_rev":"54-b0c847fb36431178a2a42d4141d63740","name":"react-easy-state","time":{"modified":"2022-06-25T20:48:32.949Z","created":"2017-05-24T13:33:34.318Z","1.0.0":"2017-05-24T13:33:34.318Z","1.0.1":"2017-05-24T13:35:55.667Z","1.0.2":"2017-05-25T13:41:25.592Z","1.0.3":"2017-05-25T20:08:45.240Z","1.0.4":"2017-06-07T15:15:53.225Z","1.0.5":"2017-07-20T14:21:23.738Z","2.0.0":"2017-08-11T15:15:59.639Z","2.0.1":"2017-08-13T20:23:05.926Z","2.0.2":"2017-08-14T08:49:58.742Z","2.0.3":"2017-08-28T07:12:00.428Z","3.0.0":"2017-08-29T19:07:25.676Z","3.0.1":"2017-09-10T13:40:27.378Z","4.0.0":"2018-01-13T17:57:12.695Z","4.0.1":"2018-01-14T11:28:12.893Z","4.1.0":"2018-01-25T13:36:35.945Z","4.1.1":"2018-02-04T19:14:25.945Z","4.1.2":"2018-02-09T19:22:28.306Z","5.0.0":"2018-02-14T17:08:18.575Z","5.0.1":"2018-04-20T06:21:49.767Z","5.0.2":"2018-05-16T16:55:42.618Z","5.1.0":"2018-05-17T17:28:26.277Z","6.0.0":"2018-10-03T12:49:50.049Z","6.0.1":"2018-10-04T15:26:41.996Z","6.0.2":"2018-10-04T15:30:07.384Z","6.0.3":"2018-10-04T22:52:32.448Z","6.0.4":"2018-10-05T16:01:54.716Z","6.0.5":"2018-10-27T12:08:34.158Z","6.1.0-beta.0":"2018-11-22T20:40:16.284Z","6.0.6":"2018-11-25T09:43:33.103Z","6.1.0-beta.1":"2019-01-30T09:49:53.727Z","6.1.0-beta.2":"2019-01-30T10:06:34.809Z","6.1.0-beta.3":"2019-01-30T10:36:24.723Z","6.1.0-beta.4":"2019-01-30T13:14:44.216Z","6.1.0-beta.5":"2019-01-30T13:21:18.986Z","6.1.0-beta.6":"2019-01-30T13:45:59.941Z","6.1.0-beta.7":"2019-01-30T14:03:45.698Z","6.1.0-beta.8":"2019-01-30T15:13:58.603Z","6.1.0-beta.9":"2019-01-30T16:51:18.213Z","6.1.0-beta.10":"2019-01-30T17:13:33.792Z","6.1.0-beta.11":"2019-01-30T17:19:53.267Z","6.1.0-beta.12":"2019-01-30T17:22:07.970Z","6.1.0-beta.13":"2019-01-30T18:20:58.174Z","6.1.0-beta.14":"2019-01-30T18:39:56.365Z","6.1.0":"2019-01-31T12:58:47.385Z","6.1.1-beta.1":"2019-02-06T09:54:50.082Z","6.1.1":"2019-02-06T10:14:05.572Z","6.1.2":"2019-05-22T16:23:23.159Z","6.1.3":"2019-05-23T18:55:09.834Z"},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"dist-tags":{"latest":"6.1.3","beta":"6.1.1-beta.1"},"versions":{"1.0.1":{"name":"react-easy-state","version":"1.0.1","description":"Easy State replaces React's setState with plain native JavaScript","main":"dist/easyState.js","module":"src/easyState.js","scripts":{"build":"webpack","test":"nyc --reporter=lcov --reporter=text mocha src/*.test.js","lint":"standard src/*"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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":"3"},"devDependencies":{"babel-core":"6.24.1","babel-loader":"7.0.0","babel-plugin-transform-decorators-legacy":"1.3.4","babel-preset-es2015":"6.24.1","babel-preset-react":"6.24.1","babel-preset-stage-0":"6.24.1","chai":"3.5.0","classnames":"^2.2.5","enzyme":"^2.8.2","mocha":"2.5.3","nyc":"10.3.2","pre-push":"0.1.1","react":"15.5.4","reify":"0.11.0","sinon":"2.3.1","sinon-chai":"2.10.0","standard":"7.1.2","webpack":"2.4.1"},"engines":{"node":">=6.0.0"},"standard":{"ignore":["src/*.test.js"]},"pre-push":["lint","test","build"],"gitHead":"27166b31e019bd5073573b9558a278622b2818fb","_id":"react-easy-state@1.0.1","_shasum":"78e132667dba33f84b276a0bb7509465ddf6ea1a","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"shasum":"78e132667dba33f84b276a0bb7509465ddf6ea1a","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-1.0.1.tgz","integrity":"sha512-UYc9TNwIs5ezITwbJyTW+2Duu+1ft5ww9TIg62RiAtHXk969xsgtXOG0MmUFM1Y2qs4Mpf1h+JDq0o1jbMoUPw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD2OUWe/OLUu6i5esit7H05g40Cb5jHA0ZWLsMGIyJLLAIhAMJTsEABNMf/CNZTGwJeabsQwlQCAmbkRvYTk2Qebp2H"}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-1.0.1.tgz_1495632954008_0.02674570376984775"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"1.0.2":{"name":"react-easy-state","version":"1.0.2","description":"Easy State replaces React's setState with plain native JavaScript","main":"dist/easyState.js","module":"src/easyState.js","scripts":{"build":"webpack","test":"nyc --reporter=lcov --reporter=text mocha src/*.test.js","lint":"standard src/*"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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":"3"},"devDependencies":{"babel-core":"6.24.1","babel-loader":"7.0.0","babel-plugin-transform-decorators-legacy":"1.3.4","babel-preset-es2015":"6.24.1","babel-preset-react":"6.24.1","babel-preset-stage-0":"6.24.1","chai":"3.5.0","classnames":"^2.2.5","enzyme":"^2.8.2","mocha":"2.5.3","nyc":"10.3.2","pre-push":"0.1.1","react":"15.5.4","reify":"0.11.0","sinon":"2.3.1","sinon-chai":"2.10.0","standard":"7.1.2","webpack":"2.4.1"},"engines":{"node":">=6.0.0"},"standard":{"ignore":["src/*.test.js"]},"pre-push":["lint","test","build"],"gitHead":"ee88ee098786c6d5de52dd7d29711e5ed29c9c88","_id":"react-easy-state@1.0.2","_shasum":"56d04ae47110801ae3152299bce0fe8664fd1e8c","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"shasum":"56d04ae47110801ae3152299bce0fe8664fd1e8c","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-1.0.2.tgz","integrity":"sha512-YUrkH652XXlQL52n0dzBsWwa/hV1jP8KVdi9tT+s6jvMFIYzIVpvlJle1zPDPDBq7BuyYWqMiBVHWGU43u05Ew==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCqSxsIacMLe91bLHrHR6/R4BjeSoWVuLx6KcM9YikxwgIhAPlWb0EyY2fm4/e7QV7so36mfZ66Lkk9zGYrFltjBZVj"}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-1.0.2.tgz_1495719684083_0.5443719436880201"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"1.0.3":{"name":"react-easy-state","version":"1.0.3","description":"Easy State replaces React's setState with plain native JavaScript","main":"dist/easyState.js","module":"src/easyState.js","scripts":{"build":"webpack","test":"nyc --reporter=lcov --reporter=text mocha src/*.test.js","lint":"standard src/*"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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":"3"},"devDependencies":{"babel-core":"6.24.1","babel-loader":"7.0.0","babel-plugin-transform-decorators-legacy":"1.3.4","babel-preset-es2015":"6.24.1","babel-preset-react":"6.24.1","babel-preset-stage-0":"6.24.1","chai":"3.5.0","classnames":"^2.2.5","enzyme":"^2.8.2","mocha":"2.5.3","nyc":"10.3.2","pre-push":"0.1.1","react":"15.5.4","reify":"0.11.0","sinon":"2.3.1","sinon-chai":"2.10.0","standard":"7.1.2","webpack":"2.4.1"},"engines":{"node":">=6.0.0"},"standard":{"ignore":["src/*.test.js"]},"pre-push":["lint","test","build"],"gitHead":"104840cc38287fd11615a83b621b3ebca6e501c1","_id":"react-easy-state@1.0.3","_shasum":"433e2e25b5a1043e71d3414874e79e72420e5183","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"shasum":"433e2e25b5a1043e71d3414874e79e72420e5183","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-1.0.3.tgz","integrity":"sha512-ZkNO+ChnHnEuZrm1FcEJCkdcPbTX6qAZtOeohFL478FD8K6g3S7Vyjp/2wYnmDOhMcpN39i9Em/TFEUiCROx+w==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCfdce2kQ0w/arP/J8DSa3b3kYKRwRiih6EY8NvidEN3QIgcg0qe7jyOQAKXJFEuKo0u68W30J5v970eSRxCC9P1ac="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-1.0.3.tgz_1495742923891_0.25744735170155764"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"1.0.4":{"name":"react-easy-state","version":"1.0.4","description":"Easy State replaces React's setState with plain native JavaScript","main":"dist/easyState.js","module":"src/easyState.js","scripts":{"build":"webpack","test":"nyc --reporter=lcov --reporter=text mocha src/*.test.js","lint":"standard src/*"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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":"3"},"devDependencies":{"babel-core":"6.24.1","babel-loader":"7.0.0","babel-plugin-transform-decorators-legacy":"1.3.4","babel-preset-es2015":"6.24.1","babel-preset-react":"6.24.1","babel-preset-stage-0":"6.24.1","chai":"3.5.0","classnames":"^2.2.5","enzyme":"^2.8.2","mocha":"2.5.3","nyc":"10.3.2","pre-push":"0.1.1","react":"15.5.4","reify":"0.11.0","sinon":"2.3.1","sinon-chai":"2.10.0","standard":"7.1.2","webpack":"2.4.1"},"engines":{"node":">=6.0.0"},"standard":{"ignore":["src/*.test.js"]},"pre-push":["lint","test","build"],"gitHead":"a3a5be923f830643e9b3774e6310503146397cae","_id":"react-easy-state@1.0.4","_shasum":"c6f70180a0f166ef8d28f78e9e87e83dee416212","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"shasum":"c6f70180a0f166ef8d28f78e9e87e83dee416212","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-1.0.4.tgz","integrity":"sha512-dmzvyoPyHjolET1WyGCNBANBZO88WKvp5v3nqmgEV1C050KcVXK6l248+6zzoNEx1Wl/DCQl8YBRgBraCqMSyg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIENamieMbvGjzL1rdgK4PQZ4mB0DcKrQGehe1ToC5PbnAiEA1sYxQJVvYOYOkSGwrVjhGV4PXZTkSwEtPK4ujODqHfo="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-1.0.4.tgz_1496848551718_0.7718064123764634"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"1.0.5":{"name":"react-easy-state","version":"1.0.5","description":"Easy State replaces React's setState with plain native JavaScript","main":"dist/easyState.js","module":"src/easyState.js","scripts":{"build":"webpack","test":"nyc --reporter=lcov --reporter=text mocha src/*.test.js","lint":"standard src/*"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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":"3"},"devDependencies":{"babel-core":"6.24.1","babel-loader":"7.0.0","babel-plugin-transform-decorators-legacy":"1.3.4","babel-preset-es2015":"6.24.1","babel-preset-react":"6.24.1","babel-preset-stage-0":"6.24.1","chai":"3.5.0","classnames":"^2.2.5","enzyme":"^2.8.2","mocha":"2.5.3","nyc":"10.3.2","pre-push":"0.1.1","react":"15.5.4","reify":"0.11.0","sinon":"2.3.1","sinon-chai":"2.10.0","standard":"7.1.2","webpack":"2.4.1"},"engines":{"node":">=6.0.0"},"standard":{"ignore":["src/*.test.js"]},"pre-push":["lint","test","build"],"gitHead":"208b1af8415de6e2a3d4f8c05a2c24e6ef63c220","_id":"react-easy-state@1.0.5","_shasum":"10e5a6ae3c28b1301c777d9bc017f10ff03d2de0","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"shasum":"10e5a6ae3c28b1301c777d9bc017f10ff03d2de0","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-1.0.5.tgz","integrity":"sha512-7lOprDNMQJvHQFpKhbqKTmMqk/f6/gshqa22NQSdLEnrOHmpxdTOkBnq94CiWcUMYKm8j47owcFW86vIRq3NHA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCrkQHMVGEruJBzErzMVE0EExvnPWgdBxfLU4vwZBOEhwIhALdqp7Jah01iUdljSz02Y5glQdqz/2yWFXoZoL1USyOA"}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-1.0.5.tgz_1500560481557_0.7107669836841524"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"2.0.0":{"name":"react-easy-state","version":"2.0.0","description":"React Easy State provides a healthy balance of local and global state management in a simple, scalable way","main":"dist/easyState.js","module":"src/index.js","scripts":{"test":"jest --coverage","test:watch":"jest --watch","test:validate":"jest-html --css-patterns ../style.css","test:update":"jest --updateSnapshot","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint:fix":"standard --fix","build":"webpack","build-examples":"webpack --config ./webpack.examples.js","build-examples-dev":"webpack --config ./webpack.examples.js --watch","build-all":"npm run build && npm run build-examples"},"jest":{"snapshotSerializers":["./node_modules/jest-html"],"collectCoverageFrom":["**/src/**","**/examples/**","!**/examples/**/index.jsx"]},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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":"3"},"devDependencies":{"babel-core":"6.25.0","babel-eslint":"^7.2.3","babel-jest":"^20.0.3","babel-loader":"7.1.1","babel-preset-es2015":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","classnames":"2.2.5","coveralls":"^2.13.1","enzyme":"^2.9.1","enzyme-to-json":"^1.5.1","jest":"20.0.4","jest-html":"^1.3.4","moment":"2.18.1","nyc":"11.1.0","pre-push":"0.1.1","react":"15.6.1","react-dom":"15.6.1","react-test-renderer":"^15.6.1","sinon":"3.1.0","standard":"10.0.3","webpack":"^3.5.2"},"peerDependencies":{"react":"*"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["dist/*"]},"pre-push":["lint","test"],"gitHead":"097e4d1f25e9d31d03d1463fa5aa72eb1bd608a9","_id":"react-easy-state@2.0.0","_shasum":"636d377d181da33d0cf4584896b0f54bddd24279","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"shasum":"636d377d181da33d0cf4584896b0f54bddd24279","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-2.0.0.tgz","integrity":"sha512-dvt8fegQNuU6jvdhfR6KJw1NWcEly/exPVYFvJOGZnEXaDauzZs03hzPf9kyBye9H1BZ+ehdSyQ2ki/5wg2mlw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGKl22GeaUJuzbx9VirqzZBNzALt6KF2/a0dq4ZDBFJfAiBBFCno4EEK5AZsyt4I9EmY5FcDbUt/TuOLWZbPByPWpg=="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-2.0.0.tgz_1502464558079_0.01094657531939447"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"2.0.1":{"name":"react-easy-state","version":"2.0.1","description":"React Easy State provides a healthy balance of local and global state management in a simple, scalable way","main":"dist/es5.js","module":"dist/es6/index.js","scripts":{"test":"jest --coverage","test:watch":"jest --watch","test:validate":"jest-html --css-patterns ../style.css","test:update":"jest --updateSnapshot","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint:fix":"standard --fix","build":"babel ./src --out-dir dist/es6 && webpack","build-examples":"webpack --config ./webpack.examples.js","build-examples-dev":"webpack --config ./webpack.examples.js --watch","build-all":"npm run build && npm run build-examples"},"jest":{"snapshotSerializers":["./node_modules/jest-html"],"collectCoverageFrom":["**/src/**","**/examples/**","!**/examples/**/index.jsx"]},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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":"3"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"6.25.0","babel-eslint":"^7.2.3","babel-jest":"^20.0.3","babel-loader":"7.1.1","babel-preset-es2015":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","classnames":"2.2.5","coveralls":"^2.13.1","enzyme":"^2.9.1","enzyme-to-json":"^1.5.1","jest":"20.0.4","jest-html":"^1.3.4","moment":"2.18.1","nyc":"11.1.0","pre-push":"0.1.1","react":"15.6.1","react-dom":"15.6.1","react-test-renderer":"^15.6.1","sinon":"3.1.0","standard":"10.0.3","webpack":"^3.5.2"},"peerDependencies":{"react":"*"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["dist/*"]},"pre-push":["lint","test"],"gitHead":"d8693f4085195c0e39b6c8734885419f69a86b8a","_id":"react-easy-state@2.0.1","_shasum":"ce906237a738e64318e98db53af3d6e30af27746","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"shasum":"ce906237a738e64318e98db53af3d6e30af27746","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-2.0.1.tgz","integrity":"sha512-hbMCdM3QJga+j9IyBWPTB7V5YUFw2uOnD/wHl3i309il4ALpV1bqzo54nxEyabQ6PT6nZ1Z7A5nuDyN9mfRTOw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCs8uff9XNa1+UScWQO3ju8rkwQxZvL67kGkKRsrBt2qgIgCyrP0M+1H/d7SKHa8r/n510ujEgo73HaaakkdPkmyHk="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-2.0.1.tgz_1502655784293_0.4028520369902253"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"2.0.2":{"name":"react-easy-state","version":"2.0.2","description":"React Easy State provides a healthy balance of local and global state management in a simple, scalable way","main":"dist/easyState.commonJS.js","module":"dist/easyState.module/index.js","scripts":{"test":"jest --coverage","test:watch":"jest --watch","test:validate":"jest-html --css-patterns ../style.css","test:update":"jest --updateSnapshot","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint:fix":"standard --fix","build":"babel ./src --out-dir dist/easyState.module && webpack","build-examples":"webpack --config ./webpack.examples.js","build-examples-dev":"webpack --config ./webpack.examples.js --watch","build-all":"npm run build && npm run build-examples"},"jest":{"snapshotSerializers":["./node_modules/jest-html"],"collectCoverageFrom":["**/src/**","**/examples/**","!**/examples/**/index.jsx"]},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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":"3"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"6.25.0","babel-eslint":"^7.2.3","babel-jest":"^20.0.3","babel-loader":"7.1.1","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","classnames":"2.2.5","coveralls":"^2.13.1","enzyme":"^2.9.1","enzyme-to-json":"^1.5.1","jest":"20.0.4","jest-html":"^1.3.4","moment":"2.18.1","nyc":"11.1.0","pre-push":"0.1.1","react":"15.6.1","react-dom":"15.6.1","react-test-renderer":"^15.6.1","sinon":"3.1.0","standard":"10.0.3","webpack":"^3.5.2"},"peerDependencies":{"react":"*"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["dist/*"]},"pre-push":["lint","test"],"gitHead":"d67f42c09f554524dcb3f340d52b561f8d41405c","_id":"react-easy-state@2.0.2","_shasum":"bcb7ce605a1106ecddd273d2455ea00ad56046cd","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"shasum":"bcb7ce605a1106ecddd273d2455ea00ad56046cd","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-2.0.2.tgz","integrity":"sha512-IXqQqVEbD8Cf+OBcUO0xw0PC1yfmi5avI3h0kyHXB5deiRk56cqx+TKeCWPwezi5ivKWHlWUR3KTsFDuKt4hTw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEDwq9tMu9PsXNf7FIk70ZB746ruXQGkDYK6/cTWmt83AiEAhsbA+NxE89En2Cns0L4w/eUhhiNBXKkL9HqWe4pdjtA="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-2.0.2.tgz_1502700596930_0.4484343798831105"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"2.0.3":{"name":"react-easy-state","version":"2.0.3","description":"React Easy State provides a healthy balance of local and global state management in a simple, scalable way","main":"dist/easyState.es5.cjs.js","module":"dist/easyState.es5.cjs.js","scripts":{"test":"jest --coverage","test:watch":"jest --watch","test:validate":"jest-html --css-patterns ../style.css","test:update":"jest --updateSnapshot","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint:fix":"standard --fix","build":"webpack --config ./webpack.config.js","build-examples":"webpack --config ./webpack.examples.js","build-examples-dev":"webpack --config ./webpack.examples.js --watch","build-all":"npm run build && npm run build-examples && npm run transpile","transpile":"babel dist/easyState.cjs.js --out-file dist/easyState.es5.cjs.js --presets=es2015"},"jest":{"snapshotSerializers":["./node_modules/jest-html"],"collectCoverageFrom":["**/src/**","**/examples/**","!**/examples/**/index.jsx"]},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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":"3"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"6.25.0","babel-eslint":"^7.2.3","babel-jest":"^20.0.3","babel-loader":"7.1.1","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2015":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","classnames":"2.2.5","coveralls":"^2.13.1","enzyme":"^2.9.1","enzyme-to-json":"^1.5.1","jest":"20.0.4","jest-html":"^1.3.4","moment":"2.18.1","nyc":"11.1.0","pre-push":"0.1.1","react":"15.6.1","react-dom":"15.6.1","react-test-renderer":"^15.6.1","sinon":"3.1.0","standard":"10.0.3","webpack":"^3.5.2"},"peerDependencies":{"react":"*"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["dist/*"]},"pre-push":["lint","test"],"gitHead":"b308199dc9a6d2a89e2c1e710293579c8af7fc73","_id":"react-easy-state@2.0.3","_shasum":"e185c235af9536aa0f06d353a21f641dc659a408","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"shasum":"e185c235af9536aa0f06d353a21f641dc659a408","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-2.0.3.tgz","integrity":"sha512-lmrKLrgIKUL9qEzspZKIOwX8+Sc4C9YLRnC//bT3Q1BlzHprQs/+/1RgL8EuaAYV2/ao2toFzcCTLMcgBVhvFg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC9Y9+JeWNtMuyQmg02fFA9jnbes0S7v+e1HQygStbYXQIgPa2CIEL2J2f6kvs/5RD7018sBc58RkVvIRturthdZRM="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-2.0.3.tgz_1503904318358_0.06135825905948877"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"3.0.0":{"name":"react-easy-state","version":"3.0.0","description":"React Easy State provides a healthy balance of local and global state management in a simple, scalable way","main":"dist/cjs.es5.js","module":"dist/esm.es5.js","files":["dist"],"scripts":{"test":"jest --coverage","test:watch":"jest --watch","test:validate":"jest-html --css-patterns ../style.css","test:update":"jest --updateSnapshot","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint:fix":"standard --fix","build-examples":"webpack --config ./webpack.examples.js","build-examples-dev":"webpack --config ./webpack.examples.js --watch","build":"rollup --config ./rollup.config.js && npm run transpile && npm run minify","transpile":"buble dist/cjs.es6.js --yes dangerousForOf -o dist/cjs.es5.js && buble dist/esm.es6.js --yes dangerousForOf --no modules -o dist/esm.es5.js","minify":"minify dist/cjs.es6.js --o dist/cjs.es6.min.js && minify dist/cjs.es5.js --o dist/cjs.es5.min.js && minify dist/esm.es6.js --o dist/esm.es6.min.js && minify dist/esm.es5.js --o dist/esm.es5.min.js"},"jest":{"snapshotSerializers":["./node_modules/jest-html"],"collectCoverageFrom":["**/src/**","**/examples/**","!**/examples/**/dist/**","!**/examples/**/index.jsx"]},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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":"3"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"6.25.0","babel-eslint":"^7.2.3","babel-jest":"^20.0.3","babel-loader":"7.1.1","babel-minify":"^0.2.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.15.2","classnames":"2.2.5","coveralls":"^2.13.1","enzyme":"^2.9.1","enzyme-to-json":"^1.5.1","jest":"20.0.4","jest-html":"^1.3.4","moment":"2.18.1","nyc":"11.1.0","pre-push":"0.1.1","react":"15.6.1","react-dom":"15.6.1","react-test-renderer":"^15.6.1","rollup":"^0.49.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"3.1.0","standard":"10.0.3","webpack":"^3.5.2"},"peerDependencies":{"react":"*"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["dist/*"]},"pre-push":["lint","test","build-examples"],"gitHead":"037818a4ee7b38ef072e6164822a1e8db39893d9","_id":"react-easy-state@3.0.0","_shasum":"c95b9969dc300dfc9d83935b7b17b94ae903f437","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.10.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"shasum":"c95b9969dc300dfc9d83935b7b17b94ae903f437","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-3.0.0.tgz","integrity":"sha512-1bzPobyyi0YQ86xWzv1RTpW1Vgl81P1XUCqWgn2osGFXgVqCY6lkZS1AtT4bDP2Wc3GpGW4dTm4Kan298d7SMA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIG4J25Szylex2zHkvTuyIJZFlWgk4Zl2pZIx2ZCxItZeAiEAtMBmx6ggcKrKndYONTZsUH7vNEyR9TSKtpKjsBT/9CI="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-3.0.0.tgz_1504033644588_0.8193673479836434"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"3.0.1":{"name":"react-easy-state","version":"3.0.1","description":"React Easy State provides a healthy balance of local and global state management in a simple, scalable way","main":"dist/cjs.es5.js","module":"dist/es.es5.js","files":["dist"],"scripts":{"test":"jest --coverage","test-watch":"jest --watch","test-validate":"jest-html --css-patterns ../style.css","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"standard --fix","build-examples":"webpack --config ./webpack.examples.js","build-examples-dev":"webpack --config ./webpack.examples.js --watch","build":"node ./scripts/build.js"},"jest":{"snapshotSerializers":["./node_modules/jest-html"],"collectCoverageFrom":["**/src/**","**/examples/**","!**/examples/**/dist/**","!**/examples/**/index.jsx"]},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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":"^3.1.3"},"peerDependencies":{"react":"*"},"devDependencies":{"babel-cli":"^6.24.1","babel-core":"6.25.0","babel-eslint":"^7.2.3","babel-jest":"^20.0.3","babel-loader":"7.1.1","babel-minify":"^0.2.0","babel-plugin-external-helpers":"^6.22.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.15.2","classnames":"2.2.5","coveralls":"^2.13.1","del":"^3.0.0","enzyme":"^2.9.1","enzyme-to-json":"^1.5.1","jest":"20.0.4","jest-html":"^1.3.4","moment":"2.18.1","nyc":"11.1.0","pre-push":"0.1.1","react":"15.6.1","react-dom":"15.6.1","react-test-renderer":"^15.6.1","rollup":"^0.49.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"3.1.0","standard":"10.0.3","webpack":"^3.5.2"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["dist/*"]},"pre-push":["lint","test","build-examples"],"gitHead":"fdfc9b000fdf503c612ced09f3eb1d3a7960273d","_id":"react-easy-state@3.0.1","_npmVersion":"5.3.0","_nodeVersion":"8.4.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-+U+eIsd9xIGHFHLdMdN2MaNAo1Qf6s5b7dQA1uC8flKytXTygC9dHTiruCCumXqpJLWwTxpoFmpTqYOY32jF6w==","shasum":"0854d65ebeff5479e2aef203a4f8a4de235467d3","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-3.0.1.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGlnKwdkRt2C+kakVjsE9+V5R0bMWd3WFZc+Oy0pZEJVAiEA7w6rApQl557TtGJ/3nJ4RxJ4PFEcqWt9gXeqRCyXWR0="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-3.0.1.tgz_1505050826298_0.05175116774626076"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"4.0.0":{"name":"react-easy-state","version":"4.0.0","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es5.js","module":"dist/es.es5.js","files":["dist"],"scripts":{"test":"jest --coverage","test-watch":"jest --watch","test-validate":"jest-html --css-patterns ../style.css","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/!(bundle).js' && standard --fix","build-examples":"node ./scripts/buildExamples.js","build-examples-watch":"node ./scripts/buildExamples.js --watch","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["./node_modules/jest-html"],"collectCoverageFrom":["**/src/**","**/examples/**","!**/examples/**/dist/**","!**/examples/**/index.jsx"]},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.0.0"},"peerDependencies":{"react":"*"},"devDependencies":{"babel-core":"6.25.0","babel-eslint":"^7.2.3","babel-loader":"7.1.1","babel-minify":"^0.2.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.15.2","classnames":"2.2.5","coveralls":"^2.13.1","del":"^3.0.0","enzyme":"^2.9.1","enzyme-to-json":"^1.5.1","jest":"20.0.4","jest-html":"^1.3.4","markdown-toc":"^1.1.0","moment":"2.18.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"15.6.1","react-dom":"15.6.1","react-test-renderer":"^15.6.1","rollup":"^0.49.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"3.1.0","standard":"10.0.3","webpack":"^3.5.2"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"]},"pre-push":["lint","test","build-examples"],"gitHead":"53c5636b391b7970d21a40903d8db4f2a375cc5e","_id":"react-easy-state@4.0.0","_npmVersion":"5.4.2","_nodeVersion":"8.8.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-fjiEkxPwWyGszn407oT4vRNYh7TS2am48fh76Vv4hHYCHFS9HbNU+NeThdbbOC++W48ynP/+voKdG6C5Uwzj0w==","shasum":"c4cd9665128d9eeb8293851f38ed263e0d9b4320","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-4.0.0.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBs5ypLxY/UlKteJ5BLCyZXhGgmCukmH7/M+rW4JXbs3AiEAsbIqSh9nRqZ+m+Xjjiq64B3eYhC5fN8WZxdTSKEOS0s="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-4.0.0.tgz_1515866231736_0.4714848888106644"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"4.0.1":{"name":"react-easy-state","version":"4.0.1","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es5.js","module":"dist/es.es5.js","files":["dist"],"scripts":{"test":"jest --coverage","test-watch":"jest --watch","test-validate":"jest-html --css-patterns ../style.css","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/!(bundle).js' && standard --fix","build-examples":"node ./scripts/buildExamples.js","build-examples-watch":"node ./scripts/buildExamples.js --watch","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["./node_modules/jest-html"],"collectCoverageFrom":["**/src/**","**/examples/**","!**/examples/**/dist/**","!**/examples/**/index.jsx"]},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.0.0"},"peerDependencies":{"react":"*"},"devDependencies":{"babel-core":"6.25.0","babel-eslint":"^7.2.3","babel-loader":"7.1.1","babel-minify":"^0.2.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.15.2","classnames":"2.2.5","coveralls":"^2.13.1","del":"^3.0.0","enzyme":"^2.9.1","enzyme-to-json":"^1.5.1","jest":"20.0.4","jest-html":"^1.3.4","markdown-toc":"^1.1.0","moment":"2.18.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"15.6.1","react-dom":"15.6.1","react-test-renderer":"^15.6.1","rollup":"^0.49.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"3.1.0","standard":"10.0.3","webpack":"^3.5.2"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"]},"pre-push":["lint","test","build-examples"],"gitHead":"38382fa334450f3907bd26421c4dd6fe7f4adb33","_id":"react-easy-state@4.0.1","_npmVersion":"5.4.2","_nodeVersion":"8.8.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-GR7sMAV/jWkCx2CX8wHh+PWRFQlIIW1Ky93bSuYvWYDgPmGoBiULZp/x87KipMRds6puAp756dV3tCwl9Cn9Rw==","shasum":"83d55b7bd8b3325217f4fcd91b613d4436a9cff0","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-4.0.1.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICSai5OxzuXXgZ8rNGJARq1KxbeHXZqpjKArBVL9ERg0AiEA2l/37Rd9sJbM4g6RkARyfVOXLkJiVi4GFOSFpOVIsNc="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-4.0.1.tgz_1515929291905_0.5300842770375311"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"4.1.0":{"name":"react-easy-state","version":"4.1.0","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es5.js","module":"dist/es.es5.js","types":"types/index.d.ts","files":["dist"],"scripts":{"test":"jest --coverage","test-watch":"jest --watch","test-validate":"jest-html --css-patterns ../style.css","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/!(bundle).js' && standard --fix","build-examples":"node ./scripts/buildExamples.js","build-examples-watch":"node ./scripts/buildExamples.js --watch","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["./node_modules/jest-html"],"collectCoverageFrom":["**/src/**","**/examples/**","!**/examples/**/dist/**","!**/examples/**/index.jsx"]},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.0.0"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.25.0","babel-eslint":"^7.2.3","babel-loader":"7.1.1","babel-minify":"^0.2.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.15.2","classnames":"2.2.5","coveralls":"^2.13.1","del":"^3.0.0","enzyme":"^2.9.1","enzyme-to-json":"^1.5.1","jest":"20.0.4","jest-html":"^1.3.4","markdown-toc":"^1.1.0","moment":"2.18.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"15.6.1","react-dom":"15.6.1","react-test-renderer":"^15.6.1","rollup":"^0.49.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"3.1.0","standard":"10.0.3","webpack":"^3.5.2"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"]},"pre-push":["lint","test","build-examples"],"gitHead":"0fb21f84eb9de686cf95c8cd1ec4192388d83a2c","_id":"react-easy-state@4.1.0","_npmVersion":"5.4.2","_nodeVersion":"8.8.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-5wVqOBMnBouUI9bAb0cOJwc0AFcdaAX5X9usVngt8Pq6bn0AJwilzv+/kq3pUYBvOVIKyU8mZ1y73pautUNwzA==","shasum":"0a8bca59ca66f213da97de319d6b9eb409a128af","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-4.1.0.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCGMOatW8S5icrMUIyQqyknsPWVimye6khLVF5nlj0lOQIgd54mk6KFEvmHF19man+PwtBYXchdrnsOklfuf6ldNXc="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-4.1.0.tgz_1516887395820_0.05173743423074484"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"4.1.1":{"name":"react-easy-state","version":"4.1.1","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es5.js","module":"dist/es.es5.js","types":"types/index.d.ts","files":["dist","types"],"scripts":{"test":"jest --coverage","test-watch":"jest --watch","test-validate":"jest-html --css-patterns ../style.css","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/!(bundle).js' && standard --fix","build-examples":"node ./scripts/buildExamples.js","build-examples-watch":"node ./scripts/buildExamples.js --watch","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["./node_modules/jest-html"],"collectCoverageFrom":["**/src/**","**/examples/**","!**/examples/**/dist/**","!**/examples/**/index.jsx","!**/examples/stopWatch/**"]},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.0.0"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.25.0","babel-eslint":"^7.2.3","babel-loader":"7.1.1","babel-minify":"^0.2.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.15.2","classnames":"2.2.5","coveralls":"^2.13.1","del":"^3.0.0","enzyme":"^2.9.1","enzyme-to-json":"^1.5.1","jest":"20.0.4","jest-html":"^1.3.4","markdown-toc":"^1.1.0","moment":"2.18.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"15.6.1","react-dom":"15.6.1","react-test-renderer":"^15.6.1","rollup":"^0.49.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"3.1.0","standard":"10.0.3","webpack":"^3.5.2"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"]},"pre-push":["lint","test","build-examples"],"gitHead":"44790a509ee2e150448927cfa4ca5e7303de8cb0","_id":"react-easy-state@4.1.1","_npmVersion":"5.4.2","_nodeVersion":"8.8.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-L+wy/TAqZQCvF2fHdW5jWkM4sbV6u2w4JPAtLUzdLxDcf6JfEw+CatPrWLwp0if3ZH6GsAv/Duw+kxG2bJvqTg==","shasum":"9ea7781e5b1b8caf812ee21580f51633806198fa","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-4.1.1.tgz","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCwd4gCa4dW4voDwd8WOeC6arc70XdnmYqlNGm/eAz0ewIgFji/8GZKf8QjqB5T9UwUaNocCiCY0vry144PpWg06RE="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state-4.1.1.tgz_1517771664903_0.005294462898746133"},"directories":{},"deprecated":"This package is moved to @risingstack/react-easy-state."},"4.1.2":{"name":"react-easy-state","version":"4.1.2","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es5.js","module":"dist/es.es5.js","types":"types/index.d.ts","files":["dist","types"],"scripts":{"test":"jest --coverage","test-watch":"jest --watch","test-validate":"jest-html --css-patterns ../style.css","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/!(bundle).js' && standard --fix","build-examples":"node ./scripts/buildExamples.js","build-examples-watch":"node ./scripts/buildExamples.js --watch","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["./node_modules/jest-html"],"collectCoverageFrom":["**/src/**","**/examples/**","!**/examples/**/dist/**","!**/examples/**/index.jsx","!**/examples/stopWatch/**"]},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.0.0"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.25.0","babel-eslint":"^7.2.3","babel-loader":"7.1.1","babel-minify":"^0.2.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.15.2","classnames":"2.2.5","coveralls":"^2.13.1","del":"^3.0.0","enzyme":"^2.9.1","enzyme-to-json":"^1.5.1","jest":"20.0.4","jest-html":"^1.3.4","markdown-toc":"^1.1.0","moment":"2.18.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"15.6.1","react-dom":"15.6.1","react-test-renderer":"^15.6.1","rollup":"^0.49.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"3.1.0","standard":"10.0.3","webpack":"^3.5.2"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"]},"pre-push":["lint","test","build-examples"],"gitHead":"19ce05246c04366356ec86b302805d783f440783","_id":"react-easy-state@4.1.2","_npmVersion":"5.4.2","_nodeVersion":"8.8.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-73SePHbK0WfVU283RcoNF7iuIVDxfSKr7SCqc5pXfEYwdP1KF2bhdpGeID1mVfvGxFMDEZ3Q9VsBikfWbEwByQ==","shasum":"86fd6c7e0a469e2c425a26f3daca23bc17620a2c","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-4.1.2.tgz","fileCount":16,"unpackedSize":93882,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCVMBanTd5+YsKs/APZwXEDJJ2mYSiwQfCjx1JNTPLLswIgBEy8XzzLA31MX/jl9I4UAcIisSfEmdAB0/4upeis4qU="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_4.1.2_1518204147547_0.5503059041493392"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"5.0.0":{"name":"react-easy-state","version":"5.0.0","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es5.js","module":"dist/es.es5.js","types":"types/index.d.ts","files":["dist","types"],"scripts":{"test":"jest --coverage","test-watch":"jest --watch","test-validate":"jest-html --css-patterns ../style.css","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/!(bundle).js' && standard --fix","build-examples":"node ./scripts/buildExamples.js","build-examples-watch":"node ./scripts/buildExamples.js --watch","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["./node_modules/jest-html"],"collectCoverageFrom":["**/src/**","**/examples/**","!**/examples/**/dist/**","!**/examples/**/index.jsx","!**/examples/stopWatch/**"]},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1.1"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.25.0","babel-eslint":"^7.2.3","babel-loader":"7.1.1","babel-minify":"^0.2.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.15.2","classnames":"2.2.5","coveralls":"^2.13.1","del":"^3.0.0","enzyme":"^2.9.1","enzyme-to-json":"^1.5.1","jest":"20.0.4","jest-html":"^1.3.4","markdown-toc":"^1.1.0","moment":"2.18.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"15.6.1","react-dom":"15.6.1","react-test-renderer":"^15.6.1","rollup":"^0.55.5","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"3.1.0","standard":"10.0.3","webpack":"^3.5.2"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"globals":["__REACT_EASY_STATE_DEVTOOL__"]},"pre-push":["lint","test","build-examples"],"gitHead":"600084bf7f78d17bb6048111f255b54eba4bcdbe","_id":"react-easy-state@5.0.0","_npmVersion":"5.4.2","_nodeVersion":"8.8.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-+T3XWQDBxM8wz2V8r7K6WzsWN51Ux9UODqSmm1gDMmVPzDvvh/nITeKSEW5ADs57sd7lTIjcYB6LgG+oN5Zxqw==","shasum":"1f114a4695779d561cdb533a86b8fe361e0a20f0","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-5.0.0.tgz","fileCount":16,"unpackedSize":82757,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD1Cnt0uBsf+j/05n2qotkVCHDWUQUTIsqhqmMhWqWLrgIgcHWV6SbH7nlkUPb8+uW1NDuRk1TfhUSq1Zq9A6BksnQ="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_5.0.0_1518628097694_0.053295816880268854"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"5.0.1":{"name":"react-easy-state","version":"5.0.1","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es5.js","module":"dist/es.es5.js","types":"types/index.d.ts","files":["dist","types"],"scripts":{"test":"jest --coverage","test-watch":"jest --watch","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["enzyme-to-json/serializer"],"collectCoverageFrom":["**/src/**","**/examples/**/*.{js,jsx}","!**/examples/**/build/**","!**/examples/**/index.js","!**/examples/stop-watch/**","!**/examples/**/beer-finder/**"],"setupTestFrameworkScriptFile":"./scripts/testSetup.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1.1"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.26.0","babel-eslint":"^7.2.3","babel-loader":"7.1.2","babel-minify":"^0.3.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.19.3","classnames":"2.2.5","coveralls":"^3.0.0","del":"^3.0.0","enzyme":"^3.3.0","enzyme-adapter-react-16":"^1.1.1","enzyme-to-json":"^3.3.1","jest":"^22.3.0","markdown-toc":"^1.1.0","moment":"2.20.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"^16.3.0","react-dom":"^16.3.0","react-test-renderer":"^16.3.0","rollup":"^0.56.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"^4.3.0","standard":"^10.0.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"cf090d359d4d21789c4c6511b5b755f8adacd382","_id":"react-easy-state@5.0.1","_npmVersion":"5.7.1","_nodeVersion":"8.8.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-yuEvY/8TiD4TUoCJFbi+FpyPkM5PdJvYH0mj3bcKYF4S9ss3UOpxp4NDSEJBjSBD27wSteNoQNjvM1OS8wkPiw==","shasum":"3676dc9a87ed0e914f4e86f99025e073bbddf620","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-5.0.1.tgz","fileCount":16,"unpackedSize":87301,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa2Yb/CRA9TVsSAnZWagAA5RoP/2TqVoRJSSMnQ+dX/Xg7\naZRDV2DtJVUFYt76VH9Eg3LTaDW+SoN4JMod5A8gKwDfc985RGPbc1r0MxYQ\nBjfYtH1+KoMzSaCKb9sprQPCNO+LTOYOLFz5ns8acK5fibNT9biCHSQ6mXgl\nb2+CgJKyuly2TeRvDwetndDmDOJEh6yZQJPNEZTpFQEndEiXUQoXtnb+euSN\ndv8pqrDBudUx/yby/pSe692mPB21NDpX4oPPEiPKL7eOJDlhvaLEytC9wywO\nJFixSifxn4fnStTarJ0vZbCACwUven8qehuSUJI/vUBQcSSQES7JKsiOHzAb\n/6AlsL/L9dmz54OaQ6+xe1PtSChGdQmZGBkH70iWfRumRFoNUquAlsrdozHq\nByik/r90dM9ScGA8BpEmIY8EmksWFX1eI4dsBVb7tLmS0KH58X9Ce937ZFfz\nqyJDVDXe3N5Ros6OMak0Gp4SbJoyoV/FsrXARHGLQgwHIOD4o6bz4TYdc72M\nNrR+4w8S9dplH6K/U4kVRzBkXpOuyyv28Sc4F3J8WszKk7qyra3qbUreFj6i\nYERkG7iY23yzHr15DqzvdhzKAc+tCqr4FjcSsJP/Hj87nkzsnftTAB8qwxNb\nvvypdVic11lQ7uw/IbqL9F2Hw8U9De343/2Ufe2ZTDAaZLIBIH/Tx05Y5lC8\ndmO+\r\n=iwot\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCpAo8gqU0kZldoFgUtO9Zp9A1lAj/vaRt1BlrDmV6avQIgGr7SYs7kVQ+CCvaUF3jnD0FJwfronqXO4kOx9Ioylpw="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_5.0.1_1524205309619_0.6074364883531755"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"5.0.2":{"name":"react-easy-state","version":"5.0.2","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es5.js","module":"dist/es.es5.js","types":"types/index.d.ts","files":["dist","types"],"scripts":{"test":"jest --coverage","test-watch":"jest --watch","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["enzyme-to-json/serializer"],"collectCoverageFrom":["**/src/**","**/examples/**/*.{js,jsx}","!**/examples/**/build/**","!**/examples/**/index.js","!**/examples/stop-watch/**","!**/examples/**/beer-finder/**"],"setupTestFrameworkScriptFile":"./scripts/testSetup.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1.1"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.26.0","babel-eslint":"^7.2.3","babel-loader":"7.1.2","babel-minify":"^0.3.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.19.3","classnames":"2.2.5","coveralls":"^3.0.0","del":"^3.0.0","enzyme":"^3.3.0","enzyme-adapter-react-16":"^1.1.1","enzyme-to-json":"^3.3.1","jest":"^22.3.0","markdown-toc":"^1.1.0","moment":"2.20.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"^16.3.0","react-dom":"^16.3.0","react-test-renderer":"^16.3.0","rollup":"^0.56.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"^4.3.0","standard":"^10.0.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"d8568b49846c2450ed63411202ea0d2cfa7b913b","_id":"react-easy-state@5.0.2","_npmVersion":"5.7.1","_nodeVersion":"8.8.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-ypIIK5UP0KoVt82VTSQYx/ta9IR+lfZD3ykaR6qcopPz6k+XvHEu1X8s3t8JWF5xYE0H5ffvjW9Fmbs2/M272w==","shasum":"13b9d9dd56faf27513431d67627de91344c52d03","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-5.0.2.tgz","fileCount":16,"unpackedSize":86353,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa/GKQCRA9TVsSAnZWagAAHi8P/jGRCi9rDsPZe7R1Fn2L\n6UOe4U/fxybnJdjBGZgXItftGhEn/vlti16ufrNNZtIsija1fdwHWgzH7izf\nmRlSCiwbQow280TPr/8i4Ltkrd0F1PhudpqzjH13keKFgahnM4QEV+h8Zy8Z\nfQn07Wt9H3WKb8rlQPNRy9RbHvi79eJ2l9vZFH6nYutMS6HpWXGPeNrT+8G7\nO418lP6ora08vVplHWe515wB0nTCXFkc/B8R260lT+/9lgko37KAMNAMlVGL\nvHkmz/iKU74v7cdGrJWlON2da5GM8bNbNGH6q1dHjRGktp7s2DWvRIsn10vz\nOqNte58l9e++c64IM51UHWR1enjIliP8W21LUNwnXe1QHVwQO/hvd/uoFTwJ\nlNb11IqgdgFWamD9eR3rlI7mgjnLI6Vz2NEHHUhzDZUgFulkPKJSBVna/0Kh\niltr4LPPA7dkK4d9JJeJlNyHE9TR6uJ/M94F6jV64u6KFmqvtvXBVpCYf5mu\nrNQVIAWyCWr4befZkzXNDDg1rf7poPq63SQq2b6dL9nEh9dxS/regmyMDslq\naJhA3MOZlSaOBOWbvZlZFnzouV9jssDT1SNsQk6/pHyHNA+i622T6HNq0ENs\nbL5ZsePrW1xVHQB/sn/Hky5nPPwLQFA6ifPuP+QTX+D1JAgFfH+zI0JKtVF1\nlefL\r\n=3I9L\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHDqoSUEcg/z6YFvSZGeNdrGFwtv6nLIU+yDQPp1lbSVAiBkaZ4jIakOI+8GtVmrKB1w+Znn/F056R6U/O6NiiUFpA=="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_5.0.2_1526489742470_0.4031034386553527"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"5.1.0":{"name":"react-easy-state","version":"5.1.0","description":"React state management with a minimal API. Made with ES6 Proxies.","main":"dist/cjs.es5.js","module":"dist/es.es5.js","types":"types/index.d.ts","files":["dist","types"],"scripts":{"test":"jest --coverage","test-watch":"jest --watch","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["enzyme-to-json/serializer"],"collectCoverageFrom":["**/src/**","**/examples/**/*.{js,jsx}","!**/examples/**/build/**","!**/examples/**/index.js","!**/examples/stop-watch/**","!**/examples/**/beer-finder/**"],"setupTestFrameworkScriptFile":"./scripts/testSetup.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1.1"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.26.0","babel-eslint":"^7.2.3","babel-loader":"7.1.2","babel-minify":"^0.3.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.19.3","classnames":"2.2.5","coveralls":"^3.0.0","del":"^3.0.0","enzyme":"^3.3.0","enzyme-adapter-react-16":"^1.1.1","enzyme-to-json":"^3.3.1","jest":"^22.3.0","markdown-toc":"^1.1.0","moment":"2.20.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"^16.3.0","react-dom":"^16.3.0","react-test-renderer":"^16.3.0","rollup":"^0.56.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"^4.3.0","standard":"^10.0.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"0221ed24bbfe6e4427f44a0a6ba3e6de5a5096a3","_id":"react-easy-state@5.1.0","_npmVersion":"5.7.1","_nodeVersion":"8.8.1","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-pUCnYr79ORtXlDV6Aojd+jJpbcL2e49eTaBELFybOLrPUJp5CIRyzcrYwmVBOi2e+USjkTObO392Q+YCEzv/Pw==","shasum":"eb7219d491f2fc98e26b00d6ae6163493935d6f0","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-5.1.0.tgz","fileCount":16,"unpackedSize":100901,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa/bu8CRA9TVsSAnZWagAA7IcP/i7Il/r2QwTwWLZ4S9JB\nPRVGP5z69AeN871ZA84h+h6BrwWCbY7sQhBmyQoe7Ugb5oq0Xc74lxepnjoy\nGq94sSv9EKWe8alntsX2AaDsyZkI46v+Iq8y+bi5uw8V1bvM7YTmfoaZbl5K\nVlqJoWCwOCp/TomsgXhGziUSok5krON/7OpXuhKtuaiEhGI/6WNsPJFjjVpT\na+iR1SFaW5cNVRD6fv/TUWcSqXRH1+0AWUdpOSFxyDcSjXoEiBiPeAB2estP\nqcPg4FSMuFDV75fZ5EMPrJFo/NU8qG+xWfuOtPpPuS9NWDmtHmMwyX7+Z/Pz\nupM1ZE0EMedGvVQ/hxVvSJOSfxA3kIW0+H1XlfLIaX7xZtqtM5aVp3zknE6P\nUP1SsXqYNMafrwtgYdXILgRgrPOyOyGTXy4mk/ZOBg3mQWuQUX26lQXgogy+\nckWMFTnjHf2j2AIyfRsG1+aXzgUAXuVZPK2LfmMccH16xP0uOZh9mhdEWT8V\nAgSNQxEBDhujWztzywvx/evXBjZMQ15b48in7EkXiefDZHDuGKAp51+11Ujz\nI5s8s8qhjGlx8Pbw/7QdWKBzEl7+DDOQyUMpEG3rG9gEAXhOgC3yT0cBUIUQ\nE5LkWzfv8qpo3YpA8mLKIx6NfpuBxzs45/hk6MLIX++m4lADvJQqT5iDERJD\nCtJB\r\n=fjuL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICrb52F6xShGRrhmV84Dnrn0wfCJNI0LrO5Y8Z1WnnqLAiBLn42nT5mKsFiLEal27xjuaHUym5BBCcm9HWciQH+dlg=="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_5.1.0_1526578106191_0.5821189119358394"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"6.0.0":{"name":"react-easy-state","version":"6.0.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":"jest --coverage","test-watch":"jest --watch","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["enzyme-to-json/serializer"],"collectCoverageFrom":["**/src/**","**/examples/**/*.{js,jsx}","!**/examples/**/build/**","!**/examples/**/index.js","!**/examples/stop-watch/**","!**/examples/**/beer-finder/**"],"setupTestFrameworkScriptFile":"./scripts/testSetup.js","testURL":"http://react-easy-state.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1.1"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.26.0","babel-eslint":"^7.2.3","babel-loader":"7.1.2","babel-minify":"^0.3.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.19.3","classnames":"2.2.5","coveralls":"^3.0.0","del":"^3.0.0","enzyme":"^3.3.0","enzyme-adapter-react-16":"^1.1.1","enzyme-to-json":"^3.3.1","jest":"^22.3.0","markdown-toc":"^1.1.0","moment":"2.20.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"^16.3.0","react-dom":"^16.3.0","react-test-renderer":"^16.3.0","rollup":"^0.56.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"^4.3.0","standard":"^10.0.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](http://img.badgesize.io/https://unpkg.com/react-easy-state/dist/umd.es6.min.js?compression=gzip&label=minzip_size)](https://unpkg.com/react-easy-state/dist/umd.es6.min.js) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  * [Creating stores](#creating-stores)\n  * [Creating reactive views](#creating-reactive-views)\n  * [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [FAQ and Gotchas](#faq-and-gotchas)\n  * [What triggers a re-render?](#what-triggers-a-re-render)\n  * [When do renders run?](#when-do-renders-run)\n  * [My component renders multiple times unnecessarily](#my-component-renders-multiple-times-unnecessarily)\n  * [How do I derive local stores from props (getDerivedStateFromProps)?](#how-do-i-derive-local-stores-from-props-getderivedstatefromprops)\n  * [My store methods are broken](#my-store-methods-are-broken)\n  * [My views are not rendering](#my-views-are-not-rendering)\n  * [Naming local stores as state](#naming-local-stores-as-state)\n* [Platform support](#platform-support)\n* [Performance](#performance)\n* [How does it work?](#how-does-it-work)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\n\nEasy State has two rules.\n\n1.  Always wrap your components with `view`.\n2.  Always wrap your state store objects with `store`.\n\n```js\nimport React from 'react'\nimport { store, view } from 'react-easy-state'\n\nconst clock = store({ time: new Date() })\nsetInterval(() => (clock.time = new Date()), 1000)\n\nexport default view(() => <div>{clock.time.toString()}</div>)\n```\n\nThis is enough for it to automatically update your views when needed - no matter how exotically you mutate your state stores. With this freedom you can invent and use your personal favorite state management patterns.\n\n## Installation\n\n`npm install react-easy-state`\n\n<details>\n<summary><strong>Setting up a quick project</strong></summary>\n\nEasy State supports [Create React App](https://github.com/facebookincubator/create-react-app) 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\n\n### Creating stores\n\n`store` creates a state store from the passed object and returns it. State stores are just like normal JS objects. (To be precise, they are transparent reactive proxies of the original object.)\n\n```js\nimport { store } from 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\n// stores behave like normal JS objects\nuser.name = 'Bob'\n```\n\n### Creating reactive views\n\nWrapping your components with `view` turns them into reactive views. A reactive view re-renders whenever a store's property - used inside its render - changes.\n\n```js\nimport React, { Component } from 'react'\nimport { view, store } from 'react-easy-state'\n\nconst user = store({ name: 'Bob' })\n\nclass HelloComp extends Component {\n  onChange = ev => (user.name = ev.target.value)\n\n  // the render is triggered whenever user.name changes\n  render() {\n    return (\n      <div>\n        <input value={user.name} onChange={this.onChange} />\n        <div>Hello {user.name}!</div>\n      </div>\n    )\n  }\n}\n\n// the component must be wrapped with `view`\nexport default view(HelloComp)\n```\n\n**Make sure to wrap all of your components with `view` - including stateful and stateless ones. If you do not wrap a component, it will not properly render on store mutations.**\n\n<details>\n<summary><strong>Usage as a decorator</strong></summary>\n\n`view` can also be used as a class decorator with the `@view` syntax. You can learn more about decorators [here](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841).\n\n```js\nimport React, { Component } from 'react'\nimport { view, store } from 'react-easy-state'\n\nconst user = store({\n  name: 'Bob'\n})\n\n@view\nclass HelloComp extends Component {\n  onChange = ev => (user.name = ev.target.value)\n\n  // the render is triggered whenever user.name changes\n  render() {\n    return (\n      <div>\n        <input value={user.name} onChange={this.onChange} />\n        <div>Hello {user.name}!</div>\n      </div>\n    )\n  }\n}\n```\n\n_Decorators are not a standardized JavaScript feature and create-react-app does not support them yet._\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 as a component property in these cases.\n\n```js\nimport React, { Component } from 'react'\nimport { view, store } from 'react-easy-state'\n\nclass ClockComp extends Component {\n  clock = store({ time: new Date() })\n\n  componentDidMount() {\n    setInterval(() => (this.clock.time = new Date()), 1000)\n  }\n\n  render() {\n    return <div>{this.clock.time}</div>\n  }\n}\n\nexport default view(ClockComp)\n```\n\nThat's it, You know everything to master React state management! Check some of the [examples](#examples-with-live-demos) and [articles](#articles) for more inspiration or the [FAQ section](#faq-and-gotchas) for common issues.\n\n## Examples with live demos\n\n_Beginner_\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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## FAQ and Gotchas\n\n### What triggers a re-render?\n\nEasy State monitors which store properties are used inside each component's render method. If a store property changes, the relevant renders are automatically triggered. You can do **anything** with stores without worrying about edge cases. Use nested properties, computed properties with getters/setters, dynamic properties, arrays, ES6 collections and prototypal inheritance - as a few examples. Easy State will monitor all state mutations and trigger renders when needed. (Big cheer for [ES6 Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)!)\n\n### When do renders run?\n\nTriggered renders are passed to React for execution, there is no `forceUpdate` behind the scenes. This means that component lifecycle hooks behave as expected and that React Fiber works nicely together with Easy State. On top of this, you can use your favorite testing frameworks without any added hassle.\n\n### My component renders multiple times unnecessarily\n\nIf you mutate your stores inside React event handlers, this will never happen.\n\nIf you mutate your stores multiple times synchronously from outside event handlers, it can happen though. You can wrap the mutating code with `ReactDOM.flushSync` to batch the updates and trigger a single re-render only. (It works similarly to MobX's actions.)\n\n```js\nimport React from 'react'\nimport ReactDOM from 'react-dom'\nimport { view, store } from '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// this renders the component 2 times\nmutateUser()\n// this renders the component only once, after all the mutations\nReactDOM.flushSync(mutateUser)\n\n// clicking on the inner div renders the component only once,\n// because mutateUser is invoked as an event handler\nexport default view(() => (\n  <div onClick={mutateUser}>\n    name: {user.name}, age: {user.age}\n  </div>\n))\n```\n\nThis will not be necessary once React's new scheduler is ready. It currently batches `setState` calls inside event handlers only, but this will change soon.\n\n> We realize it's inconvenient that the behavior is different depending on whether you're in an event handler or not. This will change in a future React version that will batch all updates by default (and provide an opt-in API to flush changes synchronously). Until we switch the default behavior (potentially in React 17), there is an API you can use to force batching.\n\nYou can find the whole post by Dan Abramov [here](https://stackoverflow.com/a/48610973). Once the new default React scheduler is ready, you won't have to worry about multiple renders. Until then you can use `ReactDOM.flushSync` or just let it go, if you do not experience performance issues.\n\n### How do I derive local stores from props (getDerivedStateFromProps)?\n\nComponents wrapped with `view` have an extra static `deriveStoresFromProps` lifecycle method, which works similarly to the vanilla `getDerivedStateFromProps`.\n\n```js\nimport React, { Component } from 'react'\nimport { view, store } from '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 passed in 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### My store methods are broken\n\nYou should not use the `this` keyword in the methods of your state stores.\n\n```js\nconst counter = store({\n  num: 0,\n  increment() {\n    this.num++\n  }\n})\n\nexport default view(() => <div onClick={counter.increment}>{counter.num}</div>)\n```\n\nThe above snippet won't work, because `increment` is passed as a callback and loses its `this`. You should use the direct object reference - `counter` in this case - instead of `this`.\n\n```js\nconst counter = store({\n  num: 0,\n  increment() {\n    counter.num++\n  }\n})\n```\n\nThis works as expected, even when you pass store methods as callbacks.\n\n### My views are not rendering\n\nYou should wrap your state stores with `store` as early as possible to make them reactive.\n\n```js\nconst person = { name: 'Bob' }\nperson.name = 'Ann'\n\nexport default store(person)\n```\n\nThe above 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\nDo this instead of the above code.\n\n```js\nconst person = store({ name: 'Bob' })\nperson.name = 'Ann'\n\nexport default person\n```\n\n### Naming local stores as state\n\nNaming your local state stores as `state` may conflict with React linter rules, which guard against direct state mutations. Please use a more descriptive name instead.\n\n## Platform support\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Performance\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 a bit worse than 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## How does it work?\n\nUnder the hood Easy State uses the [@nx-js/observer-util](https://github.com/nx-js/observer-util) library, which relies on [ES6 Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) to observe state changes. [This blog post](https://blog.risingstack.com/writing-a-javascript-framework-data-binding-es6-proxy/) gives a little sneak peek under the hood of the `observer-util`.\n\n## Alternative builds\n\nThis library detects if you use ES6 or commonJS modules and serve the right format to you. The exposed bundles are transpiled to ES5 to support common tools - like UglifyJS minifying. If you would like a finer control over the provided build, you can specify them in your imports.\n\n* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","gitHead":"25f12686c05f3b593a0bb0fea8351f913faa4198","_id":"react-easy-state@6.0.0","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-CaMzs3yW0yGpX9NdfW1deIVhc3smjNYe8N7xxBIg0lOyrf18jS+bOdHu9iar9j14AxQ72b8Ctc49wy+J3IEoeg==","shasum":"bac5f3ec086cd41dd0751b72a6be807fdc334d7c","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.0.0.tgz","fileCount":16,"unpackedSize":113752,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbtLruCRA9TVsSAnZWagAAROMP/3+Ca/qnMFBp+cyEA8+l\n8B7upX7dsszrSuORUWQrm2w281UWRckRCjRFEbfjw75zLjhp6iv+7TkczG2d\nT/74z5wtj/gYpedJpYruW9wn7JE458Tpgb4pcUHyaCEvQcbHiKazbFdv8AUP\neYZ0258XJ5nDcwxG/YuJecJ25TO6fNIVsuU9NQu9AlFjPxbBLgo/tDiUB1OS\ngBv7VNQvJIkmmzd2j45tTzPId3blqUAKcCKz1yKhVzhzg56/PIhkOAMPKot/\nifTcPUR0t6k89WB22tOT60/6qAWeNeQaBS5kBbi/HzflttERbMluvBU6R6eh\nsBiEG9WfOrS/E/L3TwZfHBlTdnN5TCEl2mrLU+NzdEdbNOyF+paBgJ3tBFiU\nvelaF8Hnu3XU1h60xf1xvr9Ib6afoYAhLuRjak/JrU1UoAiOSylHmMmUUsK7\nBF+2mM/JL3Z3DjOUe4NDBONZN/M7na8Wpuo1OEVAWqbG/QgDuipgAa9zPwsY\n/SuP1TR6iJAbmwjuBinXk0HEKlx9F1CVY0dMf9W66F35tohOcXN+8WUm8/6j\nOrjwMGcE0ZfDvMKgggNr9JzWcE1Jff0tMSPoB8TOrjlhE7di+pQrslkx9jyY\neattNevSeV9F2/chQ9pNH/U5y9hKlHKg/dzX8ploJN47yBFtE0OS7t/ijh/h\nMiV5\r\n=oQgp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBF1GdXO/HyT/naR+zocZxM/yoXwbvLD4kog5837Mf+uAiBOo4iywjZ5vLLkDKSrGv5nPNrUTWbd02iR4k4aqyDjmA=="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.0.0_1538570989919_0.5184685380073883"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"6.0.1":{"name":"react-easy-state","version":"6.0.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":"jest --coverage","test-watch":"jest --watch","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["enzyme-to-json/serializer"],"collectCoverageFrom":["**/src/**","**/examples/**/*.{js,jsx}","!**/examples/**/build/**","!**/examples/**/index.js","!**/examples/stop-watch/**","!**/examples/**/beer-finder/**"],"setupTestFrameworkScriptFile":"./scripts/testSetup.js","testURL":"http://react-easy-state.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1.1"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.26.0","babel-eslint":"^7.2.3","babel-loader":"7.1.2","babel-minify":"^0.3.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.19.3","classnames":"2.2.5","coveralls":"^3.0.0","del":"^3.0.0","enzyme":"^3.3.0","enzyme-adapter-react-16":"^1.1.1","enzyme-to-json":"^3.3.1","jest":"^22.3.0","markdown-toc":"^1.1.0","moment":"2.20.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"^16.3.0","react-dom":"^16.3.0","react-test-renderer":"^16.3.0","rollup":"^0.56.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"^4.3.0","standard":"^10.0.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"fff99576c42097bc8d8f4db0c3f87fe6e16769df","_id":"react-easy-state@6.0.1","_npmVersion":"6.4.1","_nodeVersion":"8.12.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-CbexoPxQpHayrrCrAOH5vyG/L9p6pA+r72EduNOmSM8CaMLPQkkXLnUiLEZqynvWxfnwcN1BMH+q+wcaVasvPg==","shasum":"4f1e99c508bfbf01b0a2b67be6db252fdbe60c89","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.0.1.tgz","fileCount":16,"unpackedSize":113112,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbtjEyCRA9TVsSAnZWagAAAS4QAI7iHYfRimVKFdjxtYUw\nt14fTLxw8AYwW00OsojXxge5F0KRRqeY8jdvD00Ez1ahxuQvalWpMMnf3Fjb\nc7FZ1JezWbYx9mYYOxUEGegilGQ3LSiVEZQwwnwfGgnBFBJXuw6h+gNsGYNY\nx+1VS/Ig33IdDzLAE7/lWy9gdQmhe4Gc3Y3GXFChahhar9zEXx+cTsAbJPJH\nj08C+e65I0DW7Ypc8BP8GI0iAVdl7zftiGFrADpfP4o31woJer9bx/QJYa4P\nfdX67V4/PIA2NGilFYFTO4ZsTtkXqNz3rlEW5OKYVGLsx7mmoCA4gwNmFY1W\n2rKErZixUt9mPFAhGLSqgBB7OFAm5dP7bqsgddQJw068srX+dIELbjCretAC\nHQnkFYenaDMLrS4lb+bA8ll78QI+d2YQlY2KDjba+r1VJNUboncuXDcn1OhH\nUzuewYWHDh4ETDS22l5Esz5nQVtYh/u9QQ5SMWldfxYyN+990rrSG7MHVyeJ\ngjmLThiwZw1x1E2DfKJRJctjaT0gLJOc2DOhiyOkpaApgcV+6cGlDAf/Q/PT\n2qD62bldaL0iSFLav4i+G01jPpUZO/l8Jvn8ozKvrwX3xB7+X+YKeFirnTah\nZh1YbFUGI/Sonp7h/k+oX9j/1FS6YEoZbDETilRxtvFPmnNOolH/hQh7Ye7W\nBfDj\r\n=koE5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC6rfjpd8fUWraRnlhydRZmXXWK2UvCKma7t83JQlwwMQIhANUKC8KqqeXwTVn/USxg9IcITzc0umWXYDjIXVPCWG45"}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.0.1_1538666801849_0.7494420817122862"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"6.0.2":{"name":"react-easy-state","version":"6.0.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":"jest --coverage","test-watch":"jest --watch","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["enzyme-to-json/serializer"],"collectCoverageFrom":["**/src/**","**/examples/**/*.{js,jsx}","!**/examples/**/build/**","!**/examples/**/index.js","!**/examples/stop-watch/**","!**/examples/**/beer-finder/**"],"setupTestFrameworkScriptFile":"./scripts/testSetup.js","testURL":"http://react-easy-state.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1.1"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.26.0","babel-eslint":"^7.2.3","babel-loader":"7.1.2","babel-minify":"^0.3.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.19.3","classnames":"2.2.5","coveralls":"^3.0.0","del":"^3.0.0","enzyme":"^3.3.0","enzyme-adapter-react-16":"^1.1.1","enzyme-to-json":"^3.3.1","jest":"^22.3.0","markdown-toc":"^1.1.0","moment":"2.20.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"^16.3.0","react-dom":"^16.3.0","react-test-renderer":"^16.3.0","rollup":"^0.56.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"^4.3.0","standard":"^10.0.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"77424494c8c48a0f2d2e51ceaa97765812494823","_id":"react-easy-state@6.0.2","_npmVersion":"6.4.1","_nodeVersion":"8.12.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-GpcQVAtoJrp5yWMLyGmetoKFwwxQWz27X8oy48TvRHvFx9VAiXiJ9FIKtbmT/aFn8II+UhRuBdKHipFXCb/ESw==","shasum":"82254e26a3b26b2ed1d5d9e7c39da0edfe98d425","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.0.2.tgz","fileCount":16,"unpackedSize":117143,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDdh56N+oN0qNybKr2MhzlfnvNUJy/UgFB7YrE2ShsWlAiEA9hbrr8Mm4wgxmaVoRuhL0gHtDGBaSpcMZ3Jxvekk9rU="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.0.2_1538667007231_0.9993460762450554"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"6.0.3":{"name":"react-easy-state","version":"6.0.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":"jest --coverage","test-watch":"jest --watch","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["enzyme-to-json/serializer"],"collectCoverageFrom":["**/src/**","**/examples/**/*.{js,jsx}","!**/examples/**/build/**","!**/examples/**/index.js","!**/examples/stop-watch/**","!**/examples/**/beer-finder/**"],"setupTestFrameworkScriptFile":"./scripts/testSetup.js","testURL":"http://react-easy-state.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1.1"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.26.0","babel-eslint":"^7.2.3","babel-loader":"7.1.2","babel-minify":"^0.3.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.19.3","classnames":"2.2.5","coveralls":"^3.0.0","del":"^3.0.0","enzyme":"^3.3.0","enzyme-adapter-react-16":"^1.1.1","enzyme-to-json":"^3.3.1","jest":"^22.3.0","markdown-toc":"^1.1.0","moment":"2.20.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"^16.3.0","react-dom":"^16.3.0","react-test-renderer":"^16.3.0","rollup":"^0.56.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"^4.3.0","standard":"^10.0.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"f4bda34c4977c58c40bc81077af0e04bbf6eb271","_id":"react-easy-state@6.0.3","_npmVersion":"6.4.1","_nodeVersion":"8.12.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-96ZHNfCvyy8FX1afvfSAfxBhcFvm4bVpw5lrIQ+97r4QgZpLs3KWhe37aLcap1JzVnLsw59dHdtdaCi05k5kpw==","shasum":"122d90a64dbf3f04c3e89cd05ace53f8d8a3dcdd","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.0.3.tgz","fileCount":16,"unpackedSize":117695,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbtpmxCRA9TVsSAnZWagAANOcP/3z7xak8EagyCUE7ExO2\n4nnJwiQ3ELQNmJC8mZklKOqk3aU0JeRzkwKfOr0SLPPpN8o7kkuBUfJz4105\nbyVnxJ1ox9+awXys8XEq8SqUP+/Saw9Impl3mCqgk6Z8D/mYN8xFsaLaU0Gm\nve81Dt038u8kYRsgBRGvL1OFQSP+g4JXA50YgoLvH9Pcky8AhUJ9/AWdWVQy\nEqn6eV78d9gc/ahPgT9pWW7s3Gc9yhbl7NDyUCkhdUTIesPvbMxksn2M7Jb4\nYxNT9nA4BsV8J3fK6fhYQNovrXZNW2hYw+dC/Wmq1XLDqgVzKs/0mfoWPrWu\ncAktN9SgWV3pWexG6XB/WPkdL2NK8dmEtAbck0oCkomyGEw7cLg3soY+ABiB\n2Yv3unynObXJqhGIOzcluk/ttk19MrPlE+y/xv0mnDDnsGXXYL/4bmK8iBd6\nTcyzb1E7ntLwIJOMTpJr1dDx8WoVhh15mPC8wymiPi4Y1pwDyNcIec5irF3T\niDOww/yXbiobKwwgGsQf0QOUTBU8EC4yHys/nIt+sJdiKRR8AXP2AWejQ0Bp\n5ItUG5NsaBDmexhfyr34ZETkEbDsR5SkGsB0lYDSmsJJGM4jPghqFeGp/uom\nTFhBly4KPqtuG+afW/fHnM6Of8j+0ZX783M+u8RQKGAhaMkC2Rxgu9iVoUFE\niLXq\r\n=3PZn\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBviPB6+N4e22A4ToZFd9K9QkKAuSMH6fO2og3X9OFu2AiEAt/osPZcabp0hJPeng5OCl/rzZ/kA8OV5WVsD5irb4uQ="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.0.3_1538693552300_0.947303197259856"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"6.0.4":{"name":"react-easy-state","version":"6.0.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":"jest --coverage","test-watch":"jest --watch","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["enzyme-to-json/serializer"],"collectCoverageFrom":["**/src/**","**/examples/**/*.{js,jsx}","!**/examples/**/build/**","!**/examples/**/index.js","!**/examples/stop-watch/**","!**/examples/**/beer-finder/**"],"setupTestFrameworkScriptFile":"./scripts/testSetup.js","testURL":"http://react-easy-state.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1.1"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.26.0","babel-eslint":"^7.2.3","babel-loader":"7.1.2","babel-minify":"^0.3.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.19.3","classnames":"2.2.5","coveralls":"^3.0.0","del":"^3.0.0","enzyme":"^3.3.0","enzyme-adapter-react-16":"^1.1.1","enzyme-to-json":"^3.3.1","jest":"^22.3.0","markdown-toc":"^1.1.0","moment":"2.20.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"^16.3.0","react-dom":"^16.3.0","react-test-renderer":"^16.3.0","rollup":"^0.56.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"^4.3.0","standard":"^10.0.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"f7f1a5489636456b672907e584a1b053ead130d7","_id":"react-easy-state@6.0.4","_npmVersion":"6.4.1","_nodeVersion":"8.12.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-aJ+lje879290+jWLgWXe3/iSWT6iqKw8rwGu42qt+d17TUugqy3sW90FExLH5i4q/C0fMTE0TC6Wn9WQHjCBCw==","shasum":"94a124fe69723abcb922c15059dd444b2e3499f3","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.0.4.tgz","fileCount":16,"unpackedSize":124402,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbt4rzCRA9TVsSAnZWagAA31gQAKAyWgZJIoVxb9D38Qt1\nwQJjBgljb7F6gx2IcyrwMyrfQBi4FbvbkpMB08qA70JqJBb79GWLG9UFz71k\ncJyFQq9VaDaC6LVIvDKT/Zbi1fqx3WguQc9sPLY/xXQ7YJDcsfirF/oWuTyb\np2glbaCESD1g8tALR1Nx1ejIcsWrkz6JBUSfBQ6Og9q8s8qDWerf3qqqVned\nOSDSN84chVyv6lNV+sEZwafWOIyKdDDitYOqnfNKO1GMVfSR47cRknz/HZ3i\nOGuXwHZPj1f/eRtJ1ENPVWZHOjWYNn3JYS32paVQGD8Y8n25ZWXKYSE28Q2U\n8Kaem9CD7AUWq5EfVpuqXsUDIcQL1iCWaUTpydPBqvNYJT+ZbGnwIlByG5Na\nvV1qNxia46I35BLwzPml23GRHnU4PBsgMmAKZNpiK2e5afJvxI6DZE3U7JDE\n9pirQwogoDda+nSJtFDkJOwEhNlTVCW77CBS9WqxMQX29mBjy/DurXpqG5R5\nWpsnmbVxPe89PY3f9r/EPX0f5BkwuDOx74BsgNj1FEpLQyvHiLmMgAHiAKmq\nvKTIU5Q+L4S/fDEsRfiFV5UWM75gBDKsvpnlmPtLVDGv9BlBg3HyIW9IZSFw\neml0nMUwmdhro5mNalLsr07C8i2x27I1J4Tz7MGIc7eIZguEqE64Bwu9c1Y6\nZYvO\r\n=r9Tk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEGiIHUUTsgOD7JK+I2XUh/LrXctlflV0SMf2kXP3wk5AiEAscSQPTsWjrkdod4zg6C74tdA5IR1gdRFdOvcCYMGDcY="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.0.4_1538755314535_0.7564457796570374"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"6.0.5":{"name":"react-easy-state","version":"6.0.5","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":"jest --coverage","test-watch":"jest --watch","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["enzyme-to-json/serializer"],"collectCoverageFrom":["**/src/**","**/examples/**/*.{js,jsx}","!**/examples/**/build/**","!**/examples/**/index.js","!**/examples/stop-watch/**","!**/examples/**/beer-finder/**"],"setupTestFrameworkScriptFile":"./scripts/testSetup.js","testURL":"http://react-easy-state.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1.1"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.26.0","babel-eslint":"^7.2.3","babel-loader":"7.1.2","babel-minify":"^0.3.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.19.3","classnames":"2.2.5","coveralls":"^3.0.0","del":"^3.0.0","enzyme":"^3.3.0","enzyme-adapter-react-16":"^1.1.1","enzyme-to-json":"^3.3.1","jest":"^22.3.0","markdown-toc":"^1.1.0","moment":"2.20.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"^16.3.0","react-dom":"^16.3.0","react-test-renderer":"^16.3.0","rollup":"^0.56.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"^4.3.0","standard":"^10.0.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"20397fd2c96e555b964434c6401140ef05d3af89","_id":"react-easy-state@6.0.5","_npmVersion":"6.4.1","_nodeVersion":"8.12.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-LbO5e9Kr+mdyeC5HgD0LPZspgxfLk43U2XPVZ2Q5Sbil1tRxpOcLHZd5VsziKgOD3dOJOFl75GYcCbgGh4Nn3Q==","shasum":"e28fb8632d52a69b66e36b10967e5736ad86a7f1","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.0.5.tgz","fileCount":16,"unpackedSize":125450,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb1FVDCRA9TVsSAnZWagAADTUP/2tQ+P392dGAaUQDTSxP\ncmv3yPLUjllPwdLDQ5+LlxN2XOjCD4U6la4yOisC5WO0PPvCZNBR7wlTtTev\ngkcZPdkRUznoiuaUdL3TYqule8nK71QFv2td5ucl7QduxRCMxGJfz/FCtG24\naVoH6KEz0ENFyNh3LoAt/XFW0WXpC3O1LvrlHQcNIECTQ1m4bVdwrM6+67b8\nayMe2X79C2TuI9PLi733ctgAIPQEsrqsvS2LPHw8ErXNtx1N7f7lOYSDtXRU\nR65IYc7w71nZ/8LgRzIEADD58tX4rGIKp6zbaxI9PW2wAVhMOaFfzuGGt34p\njjYe0W77hEg94Qf4HY2O5iImnZ/NScABCBHQzAF/Prn17VkAbNKcLNzcqwvt\ny+MwjzMB9zi1YHxUD7BZCz//iru1PJttKXRwBkGLN9HMfkLxDno5Iwv2nENy\nRokirGJJK+s90vEThIpHzzi0rTqRxgQgHAm55mGBea9mYbKYbfx0UAqCYBpH\nkEszo4800ScLQFHf70hYmFX05PZ9RWM/c8mYFz20tIziDJNVxJd7KhXR7FXB\nsEpEyZl4ZxLT80FuZUBbYiP7nDLBHM3MLACgXGnlpq9AqFXtXS6euuTYWJTx\nDgMbuj+rUBu6VzpvV70qLTjq7Uct1CV9K+mcrMIppP6MEjq81RXZEjT3k7P0\nUlHw\r\n=1f1f\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICjXcxbxTy/AenKnb1BWlpRFgixKmd5zwXFodNjlnB86AiBIM2vYS/0b5P5rAFvSwdxZLpL4yHxEgWASWRPAUStptw=="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.0.5_1540642113956_0.22600989753527378"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"6.1.0-beta.0":{"name":"react-easy-state","version":"6.1.0-beta.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":"jest --coverage","test-watch":"jest --watch","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1.1"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.26.0","babel-eslint":"^7.2.3","babel-loader":"7.1.2","babel-minify":"^0.3.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.19.3","classnames":"2.2.5","coveralls":"^3.0.0","del":"^3.0.0","jest":"^22.3.0","jest-dom":"^2.1.1","markdown-toc":"^1.1.0","moment":"2.20.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"^16.7.0-alpha.0","react-dom":"^16.7.0-alpha.0","react-test-renderer":"^16.7.0-alpha.0","react-testing-library":"^5.3.0","rollup":"^0.56.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"^4.3.0","standard":"^10.0.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"jest":{"collectCoverageFrom":["**/src/**","**/examples/**/*.{js,jsx}","!**/examples/**/build/**","!**/examples/**/index.js","!**/examples/stop-watch/**","!**/examples/**/beer-finder/**"],"setupTestFrameworkScriptFile":"./scripts/testSetup.js","testURL":"http://react-easy-state.js"},"pre-push":["lint","test"],"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\n\n**Breaking change in v6:** the default bundle changed from the ES5 version to the ES6 version. If you experience problems during the build process, please check [this docs section](#alternative-builds).\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  * [Creating stores](#creating-stores)\n  * [Creating reactive views](#creating-reactive-views)\n  * [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [FAQ and Gotchas](#faq-and-gotchas)\n  * [What triggers a re-render?](#what-triggers-a-re-render)\n  * [My store methods are broken](#my-store-methods-are-broken)\n  * [My views are not rendering](#my-views-are-not-rendering)\n  * [My views render multiple times unnecessarily](#my-views-render-multiple-times-unnecessarily)\n  * [How do I derive local stores from props (getDerivedStateFromProps)?](#how-do-i-derive-local-stores-from-props-getderivedstatefromprops)\n  * [Naming local stores as state](#naming-local-stores-as-state)\n* [Platform support](#platform-support)\n* [Performance](#performance)\n* [How does it work?](#how-does-it-work)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\n\nEasy State is a transparent reactive 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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => <button onClick={counter.incr}>{counter.num}</button>)\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/solkimicreb/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\n\n`npm install react-easy-state`\n\n<details>\n<summary><strong>Setting up a quick project</strong></summary>\n\nEasy State supports [Create React App](https://github.com/facebookincubator/create-react-app) 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\n\n### Creating global stores\n\n`store` creates a state store from the passed object and returns it. State stores are just like normal JS objects. (To be precise, they are transparent reactive proxies of the original object.)\n\n```js\nimport { store } from 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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\n```js\nimport { store } from 'react-easy-state'\n\n// stores can include any valid JS structure (nested data, arrays, getters, Sets, ...)\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})\n\n// stores can be mutated in any syntactically valid way\nuser.profile.firstName = 'Bob'\ndelete user.profile.lastName\nuser.hobbies.push('reading')\n```\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\n    <div>Hello {user.name}!</div>\n  </div>\n))\n```\n\n<details>\n<summary>A single reactive component may use multiple stores inside its render.</summary>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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<br />\n\n**Make sure to wrap all of your components with `view` - including class and function ones. If you do not wrap a component, it will not properly render on store mutations.**\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, { useEffect } from 'react'\nimport { view, store } from 'react-easy-state'\n\nexport default view(() => {\n  const clock = store({ time: Date.now() })\n\n  useEffect(() => {\n    setInterval(() => (clock.time = Date.now()), 1000)\n  }, [])\n\n  return <div>{clock.time}</div>\n})\n```\n\n#### Local stores in class components\n\n```jsx\nimport React, { Component } from 'react'\nimport { view, store } from 'react-easy-state'\n\nclass ClockComp extends Component {\n  clock = store({ time: Date.now() })\n\n  componentDidMount() {\n    setInterval(() => (this.clock.time = Date.now()), 1000)\n  }\n\n  render() {\n    return <div>{this.clock.time}</div>\n  }\n}\n\nexport default view(ClockComp)\n```\n\nThat's it, You know everything to master React state management! Check some of the [examples](#examples-with-live-demos) and [articles](#articles) for more inspiration or the [FAQ section](#faq-and-gotchas) for common issues.\n\n## Examples with live demos\n\n_Beginner_\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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## FAQ and Gotchas\n\n### What triggers a re-render?\n\nEasy State monitors which store properties are used inside each component's render method. If a store property changes, the relevant renders are automatically triggered. You can do **anything** with stores without worrying about edge cases. Use nested properties, computed properties with getters/setters, dynamic properties, arrays, ES6 collections and prototypal inheritance - as a few examples. Easy State will monitor all state mutations and trigger renders when needed. (Big cheer for [ES6 Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)!)\n\n### My store methods are broken\n\nYou should avoid using the `this` keyword in the methods of your state stores.\n\n```jsx\nconst counter = store({\n  num: 0,\n  increment() {\n    this.num++\n  }\n})\n\nexport default view(() => <div onClick={counter.increment}>{counter.num}</div>)\n```\n\nThe above snippet won't work, because `increment` is passed as a callback and loses its `this`. You should use the direct object reference - `counter` in this case - instead of `this`.\n\n```js\nconst counter = store({\n  num: 0,\n  increment() {\n    counter.num++\n  }\n})\n```\n\nThis works as expected, even when you pass store methods as callbacks.\n\n### My views are not rendering\n\nYou should wrap your state stores with `store` as early as possible to make them reactive.\n\n```js\nconst person = { name: 'Bob' }\nperson.name = 'Ann'\n\nexport default store(person)\n```\n\nThe above 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\nDo this instead of the above code.\n\n```js\nconst person = store({ name: 'Bob' })\nperson.name = 'Ann'\n\nexport default person\n```\n\n### My views render multiple times unnecessarily\n\nRe-renders are batched 99% percent of the time until the end of the state changing function. You can mutate your state stores multiple times in event handlers, async functions and timer and networking callbacks without worrying about multiple renders and performance.\n\nIf you mutate your stores multiple times synchronously from exotic task sources, multiple renders may happen though. In these rare occasions 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 'react-easy-state'\n\nconst user = store({ name: 'Bob', age: 30 })\n\n// this makes sure the state changes will cause maximum one re-render,\n// no matter where this function is getting invoked from\nfunction mutateUser() {\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### How do I derive local stores from props (getDerivedStateFromProps)?\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 '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 passed in 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### Naming local stores as state\n\nNaming your local state stores as `state` may conflict with React linter rules, which guard against direct state mutations. Please use a more descriptive name instead.\n\n## Platform support\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Performance\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 a bit worse than 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## How does it work?\n\nUnder the hood Easy State uses the [@nx-js/observer-util](https://github.com/nx-js/observer-util) library, which relies on [ES6 Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) to observe state changes. [This blog post](https://blog.risingstack.com/writing-a-javascript-framework-data-binding-es6-proxy/) gives a little sneak peek under the hood of the `observer-util`.\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","gitHead":"43d90e2e227034eee420659433b2333a24bf2dad","_id":"react-easy-state@6.1.0-beta.0","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-RbxuaHZnSl/xtwF26jyg4maT7EZkcKtL4MH1rZhUeUEsynB9buiRRK7w77pTEQOG4OzKe5D/Mgypg4ibcgh8+w==","shasum":"58853d8da8ba8d9820b5ad0f3635b93d15b23606","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.0.tgz","fileCount":16,"unpackedSize":139674,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb9xQxCRA9TVsSAnZWagAAtfMP/i5lbKn1aH8ghNN3qUIP\no9XCze3DpDdKj7Mk0kJ/u/3L3pvxEWk+21+ax306d5yYlGWliOgPyPuauLpB\nRgIZPvaA/+T0OwhDK7kcfYd5+UmEFV9sJZTKdKOJK9SaDg6DhizmjiasRrD9\n2gy7Txd2ieJ1ssTNMfFCHzfhSkBIT1Kou556Qu8oSBVIhXvXXsvT7fY4feYs\na2HwPqiRJhNwUoXekdfoI36L75aFx6HJ39NdFQtTuayN3wYPDIXWuUitx/8C\n5RVI9Bi37n3R/rSSbeYAM8+zojEv+cou9mLsXA/poYHR105FeiF+O/38FYPs\nFCBwnYv01gn7zo9A3C18DMTwK/f+QFzjAJ+USQ1D22E/MvS4CB6YxABGKXZf\n1G4OsufITqirwXGATp2+umGwR+fADwesrC6aUT+IdMR+Oa/45hbOEUn91k3h\nu82ekNMuFUmTb06JMzizERwk07QS8b6QqPxxI/jB81TUtdwqXX+bLCldJeg/\nKPofIR6TjXJamDRyYq+r0RMXdGqy/nFzVc/GwxJQN2q5sVhBcm0x4x4h4KMe\nd13KMA1if3hpVZBVVTSf1YDNKxd/pyLRezLoanLF+L+g47I8BJYISbzU7fOc\nya/S5gSVCmfgpKcgrtjYAM7NBYJDuhaGT8mXUaxE1H0tu8kDQDHzbYtWvCao\n4nSY\r\n=sH4v\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAdDiqX16eN8nBmAHcklDm2lBn0TkHXgdeCZ2ti03ts3AiEA8alLu522v7CKkFb8X6ybsSD1csTKLdJQYYQ9R/O/jJM="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.0_1542919216164_0.55068789588491"},"_hasShrinkwrap":false},"6.0.6":{"name":"react-easy-state","version":"6.0.6","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":"jest --coverage","test-watch":"jest --watch","test-update":"jest --updateSnapshot","test-builds":"node ./scripts/testBuilds.js","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"jest":{"snapshotSerializers":["enzyme-to-json/serializer"],"collectCoverageFrom":["**/src/**","**/examples/**/*.{js,jsx}","!**/examples/**/build/**","!**/examples/**/index.js","!**/examples/stop-watch/**","!**/examples/**/beer-finder/**"],"setupTestFrameworkScriptFile":"./scripts/testSetup.js","testURL":"http://react-easy-state.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1.1"},"peerDependencies":{"react":"*"},"devDependencies":{"@types/react":"^16.0.35","babel-core":"6.26.0","babel-eslint":"^7.2.3","babel-loader":"7.1.2","babel-minify":"^0.3.0","babel-plugin-transform-es2015-modules-commonjs":"^6.24.1","babel-preset-es2016":"^6.24.1","babel-preset-es2017":"^6.24.1","babel-preset-react":"^6.24.1","babel-preset-stage-0":"^6.24.1","buble":"^0.19.3","classnames":"2.2.5","coveralls":"^3.0.0","del":"^3.0.0","enzyme":"^3.3.0","enzyme-adapter-react-16":"^1.1.1","enzyme-to-json":"^3.3.1","jest":"^22.3.0","markdown-toc":"^1.1.0","moment":"2.20.1","pre-push":"0.1.1","prettier":"^1.6.1","react":"^16.3.0","react-dom":"^16.3.0","react-test-renderer":"^16.3.0","rollup":"^0.56.0","rollup-plugin-auto-external":"^1.0.0","rollup-plugin-babel":"^3.0.2","rollup-plugin-node-resolve":"^3.0.0","sinon":"^4.3.0","standard":"^10.0.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"8daadf871a36cee1b1624047b2f2bfccef63a4be","_id":"react-easy-state@6.0.6","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-/Dr4qKkU3yXVTqRULqrm+Ge5fhri5QBQHwcbCRWhHn+DaDMABOjBO8e9XN9K42NipCMnrOkSKu+8YQ4ZitgevA==","shasum":"50eec0f402ed71eb71b2a642ce035416e7f817b7","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.0.6.tgz","fileCount":16,"unpackedSize":126802,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb+m7FCRA9TVsSAnZWagAAyC0P/3X0h2Tg+bsxOP8t2EaW\nGrb7DDFzKvt+BmoS81ROOdgfmZLiDQ0Lqa2vvGA5Sda9t5sqXzgMPI3RNm+r\npYh5Mhfqnrad/A4NU4l9ZwhF8p63/plv7SEQ0Qe056AJe6s71przfFgJofSI\n6s8+GITmr0u9CvGzdpeiH6izmwmiQRCYsbXlZJuXL1GKWNY6gNuFGYzIFEOP\nkOP9GNkGufIfWO1NSeTcQt/7Mit2ntISZcWtc7HJCrq0nu0ctx6y3tkD36yX\nuZ1qvBb+uq6A2fvFz+HD/YGUUPmmcd0XGE5rjd649qABp4HI2FpDDagofw5K\nXg1WZR9EfDiEs2V+X4ucuOV0ApNU3+zuiPiGr8FebUUeD/TRZx9jqjQcqFOw\nyr7HgSjAfIEDWZSHeRE5AlRhk4iEin+sEZgREcojxhxsXlsFa+7t112Qntr0\nyifP4jah2oRk3v+PgOcFEU2sUH9EqxsFxwnlhWZTF60X2OgkPbl+UH6JslwZ\nTdhiPtIdDQ3MQkJlTYdZlPSWBCQ0PspbetBZJ2O6dWiqcwatu8g8WWuvS4Wv\nnJc7LaEmde8duOf235MSp3eK6Eoc6G+c3niZ62y2znNU4cwlSKWH+bkLEapr\nboQHxbZRV+fJafaYgnxmOBoOOh/9elqHxfF0MH636LNID8udrE/SnW3n9HXa\nSZO1\r\n=hbHs\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCKU0HKsAtVJOjsL746F+PsVQXXYzAuAhuYsUhv/w0x8QIhAOfZIMmdYj/aTU6/7iMIvFoHgJrkv5TBCYZaI+NjswIH"}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.0.6_1543139012994_0.4141904700951329"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"6.1.0-beta.1":{"name":"react-easy-state","version":"6.1.0-beta.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":"jest --config ./jest.native.json && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1","nyc":"^13.1.0","save-dev":"^2.0.0","react-dom":"*","react-native":"*"},"peerDependencies":{"react":"*"},"optionalDependencies":{"react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","del":"^3.0.0","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native":"^0.58.3","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [Performance](#performance)\n* [Platform support](#platform-support)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => (<button onClick={counter.incr}>{counter.num}</button>))\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => (<div onClick={counter.increment}>{counter.num}</div>))\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => (<Table data={cloneDeep(dataStore.items)} />))\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 'react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  return <button={() => counter.num++}>{counter.num}</div>\n})\n```\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\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 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","gitHead":"7285d6dbbdffeb7ddebc335dbd7e6e42b1ce5504","_id":"react-easy-state@6.1.0-beta.1","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-UCLB+ldxDq6sbXGL9MRCOLflD9qYEaFiY8+A92bgTydlkQUe9K1zuD1dLY0ZACqVaVdPzdWI0n7TMkDC3PPsyQ==","shasum":"2f372776b961d77a6e34b0a755b4f1495f8ce086","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.1.tgz","fileCount":12,"unpackedSize":129329,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUXNCCRA9TVsSAnZWagAAbhUQAI4ZIPetY0ELdU5Ikiz+\ndulktve5J/JN29cUg2R9VX01zkbsAPPa0H2tkRT7wXY4gf0DlunEY77RbjLD\nJnMU/lE5W6mSBHKMeasFMed8AT+Gngqm1vYePgtiZraVyyveFsykIZ1Y0TgP\nuvcWaOvO2C6/2KJg6gyXabhOOHR7cC3SahaR70Qcs7EqsJDZVrXLytJ3N+em\ncqN2W4kGbJTwVVOZkHyMUJejEtO/fFY5JvpUMOAa9rjnp8oEDedt408sBYtS\nGus7+xsnTikxlELCHYu7wpiPEaFuu0RIjiAdpgxpCNoQY5GjjHTYEMBidpw+\nbMC7xh2yB6z5EGOTccgwO05cr3KaMDH0u7gJjXqKLYscwNfM7yChNwy8QA47\nuaug+Af23Y/F9DUDWRws3OVqCJjgGwZsCbivSNf0GLSvtt80e2HHTpPoOSNC\nfQXVRq8mxuJlHDX0WtEg0DYRhGUioo6Qav435R45zx8D5f3Hvblnc1T1Z4GI\nJkuBuXkYIw1TCS+vW947i10i772IDjLK5zV583YKK2iPWwPIwzlMiHL96Jv0\nQ6dJrGm/t4FhXQlzv1r70Zddy8cprZbF8MHDQqlhouEjogB9ZFwYEpOvOikY\niI5T9BRVlq+8lxK6gP+amVb81leKrVUmndziIfBhZMfsFP3D1dMLFomckXVB\nthvm\r\n=pVCh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC9q/FgLFUuCIYfeLmSAV8DR/zUo4/vZfUGMHa0WYH1jQIhAK0Q4Z30bfKuEaFMPPUJRU5uwLgR0JXBwk1PL8Q7hyBO"}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.1_1548841793632_0.977488157112318"},"_hasShrinkwrap":false},"6.1.0-beta.2":{"name":"react-easy-state","version":"6.1.0-beta.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":"jest --config ./jest.native.json && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1","nyc":"^13.1.0","save-dev":"^2.0.0","react-dom":"*","react-native":"*"},"peerDependencies":{"react":"*"},"optionalDependencies":{"react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","del":"^3.0.0","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native":"^0.58.3","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"dcd75c9984069fd0ce797fa4cb0d7a9fd7e8847a","readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [Performance](#performance)\n* [Platform support](#platform-support)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => (<button onClick={counter.incr}>{counter.num}</button>))\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => (<div onClick={counter.increment}>{counter.num}</div>))\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => (<Table data={cloneDeep(dataStore.items)} />))\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 'react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  return <button={() => counter.num++}>{counter.num}</div>\n})\n```\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\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 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","_id":"react-easy-state@6.1.0-beta.2","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-hgtgBwfDvKx4bXO0FvU7qhpJ8ZZBB0dEXvyX6NttdTivmKbTZ2xFBU75+6VEPWvryc9WzfGlYlcb+nBZfWsJtQ==","shasum":"442a1b034fc0e934d0f3ecdb44f02a4e4a0fdba2","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.2.tgz","fileCount":12,"unpackedSize":129165,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUXcrCRA9TVsSAnZWagAA8VcP/0PcBkxCBExHlVzVXxEe\nn/FDcCmc5lAoXiWuVf1ghbUbfFHca1a+p7XAVD2vaOtGuO7CEGcEROInr2/D\nw6VSkbrWm817Ea9pm9kS3wHDQC9v2dN1gDTXumxjzK5A7To/4stKvCYhIWiP\ngCHceivO/ovmXZ7I0+Keklss2A0JUxvmOCFwj79RR7c71NZhrJP9uYla61lp\nKRRgIySoUWQGHZkswVB9NleTJb+aXYWkSylVGcKPzMbHEimI376mT8YvNM4W\n4wNERtu7ogYqApBZoVx6bQJJeoYYTAJj8Psy0lUdFk6P6G+DvD+gnEF+9LRe\n6LdyNBOoYIAhr6BlSTosVJ529EUF3GoDDCnFqKf93hS+VCgXlcABZEIMaU+N\nENtrT6M/Y6alwQLPvDAAbTPxHtiO/H7oMUicfsOmEKv1H32kyP2MUDhCL2sY\nhHXO6UX47zcGtV+eRXWsvoM/jQfLT13AXWzAjACYxLDns3v8xEwmwr6waxoB\npRV7vYlyim8rWFffodYtvpSSc7RfeBXiIgT/UJv3CNmFENQVxfpBDWL2HKPc\nrClZ5TBJ3yV8wfLCHwo1tVvG9k1qOPCGwfXan8zoZ9hbEe7GP946W7eFMzlu\nkBJAZgZcijUfr1wU4GePgEZCMicoA8+W9RhSNkcGbxIS1UNnU5mVfzyEstT6\nCQZW\r\n=FEJi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDaUfbW0W2ACUOO/md2PreHyjojvsHcCXiMz3AW8p01zAiA1iuJVYrcMmQ9vBQmSCQW2vQObC8s73lnF01lGTrby+w=="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.2_1548842794694_0.37528618157440485"},"_hasShrinkwrap":false},"6.1.0-beta.3":{"name":"react-easy-state","version":"6.1.0-beta.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":"jest --config ./jest.native.json && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1","react-dom":"*","react-native":"*"},"peerDependencies":{"react":"*"},"optionalDependencies":{"react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","del":"^3.0.0","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"a27cf80935eea6e9150a797602175598cb5af765","readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [Performance](#performance)\n* [Platform support](#platform-support)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => (<button onClick={counter.incr}>{counter.num}</button>))\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => (<div onClick={counter.increment}>{counter.num}</div>))\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => (<Table data={cloneDeep(dataStore.items)} />))\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 'react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  return <button={() => counter.num++}>{counter.num}</div>\n})\n```\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\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 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","_id":"react-easy-state@6.1.0-beta.3","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-XaUtwLPq+zy/7B42thCaIPnH/myDc5GA0uDrouTCUDPuw0bQrU4s6GrMD9EkAmNWFkZW/1ewyXDVAnzXTUneuQ==","shasum":"20328c4532d2677a9a4fef8f883415c3b6522c10","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.3.tgz","fileCount":12,"unpackedSize":132228,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUX4pCRA9TVsSAnZWagAAvLUP/RLJB/zrov7b29J6MKUu\nXeV5klRocNGwXxLRY2Gjww8HRXH9BYp95kMj/NgZfcFet73k/qPGQ9/jctwv\nVysdHXiJ+CED5fCJk1JB+F0X/XHG2aO+FZb31rMSXhONXSZzB8fnfZH01Rg2\nmEwJtW/obZ2S4ZTuYfiNdOmRBYsk0J26IYF57GNqyqQDRGsIaiGIHE8AaWUW\nLlIYqcH3VC05cW/y4bSUY8LdwbXa3y6/xKc5E19lkJwfOPCXHNTShPBEOhB6\nYaSbAlTF2oP77IjnKEcV3FS9sraIKcGmbbxqOisbbxDdJwE/DYihSEKZrrMA\ntPn9WprILHFZ5+8/nQfuK1uADAhGXr3kZB0QiLSFbdWDXx6UFfLZ2m0RLJb9\n/9vvUPLakvCMgl4NkCQg6owu8JNUyHNvBI4CFOZuEoF3CSQOYLqVR8xZb2B4\nVQHi1dbr9IZS9BVylslSMdyrpx8nR8quoE9gJ1rtqx5LHmhSOesO1PHbZ6JS\nfT0Xl5PkbbGLSOrMs813zJ2Mjr3k2+7TDMRS0NVBhBE5dH4HrPZ27KFOnGV9\nYtV1FawDrV00LlB53tl1NFgKOpl/LM6WstBYzTSkmA4DDJOwnhJgw+5oV+rW\nJGfzjs0hNKvMv0DuFYd+JhyANxnkGHyAaL7Yma1fYUjA0o+2kjQoHx58BpLI\njNhf\r\n=hNdx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIF1nbpfPHIgqztfEtbWy+srgG7EjhRISuP9SOWrFht1+AiA4aJkdDCZ/KlzZyn5pQXa8inhk5K80kWRKRhS9NdqzUQ=="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.3_1548844584610_0.24904943634898724"},"_hasShrinkwrap":false},"6.1.0-beta.4":{"name":"react-easy-state","version":"6.1.0-beta.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":"jest --config ./jest.native.json && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1","react-dom":"*","react-native":"*"},"peerDependencies":{"react":"*","react-dom":"*","react-native":"*"},"optionalDependencies":{"react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","del":"^3.0.0","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [Performance](#performance)\n* [Platform support](#platform-support)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => (<button onClick={counter.incr}>{counter.num}</button>))\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => (<div onClick={counter.increment}>{counter.num}</div>))\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => (<Table data={cloneDeep(dataStore.items)} />))\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 'react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  return <button={() => counter.num++}>{counter.num}</div>\n})\n```\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\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 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","gitHead":"748382760a435e2565365304525732d695a1d8bd","_id":"react-easy-state@6.1.0-beta.4","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-dJAJZJSiHp8WSc4oFv7FolwcqrXjPwL/DtmVtnaMGGjW1hp4/t55sNmpM5CSXFWkLhMHWL7Rt4pqXw4UZlFbow==","shasum":"22d1499729a928abd5c8980fe7c86bd4457983f8","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.4.tgz","fileCount":12,"unpackedSize":131893,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUaNECRA9TVsSAnZWagAA7ZoP/j1BgpZqoMzjEuPnFBfM\nOEVLHppnhKqX7wlWK+DwnrhTPizCOnAQLVk58nwWJqMNo3NgalC/IL7WUuUP\nTD+x5DajEwwp6DA1pI6NaYzVGqH2Blm2PbPXbO/+WnCQWuncicNSM4xLoDhD\n9uGC1mDPaX/7ErBsG7Y1/AOSbk/9spzMjvJ7dRGHGfiQN73GGv8aSgpfEihK\nBAAEMQ156ATOTb5PD1goUg0rJNfWFlg12nN5maqZvQyg0NnDh2cY4Q25O+WL\nbr5xD4WGdZodJzeSvaP4BAI4f6mHe/oppKKZrSUGvGtQQ/pL8Jdk+enTZv5Z\nJwwQAaLlW5Regd/0qJlmTciyxZZYNV3Me3RbMSg9hr0l1TgY0hKiEk7rH/0o\nwjzhWwtA1puntnsweQLUKmrbMvkDxphKQWmi02G1FqgCZFqXPoQhV4DDsP6P\nsXeboiJtkwrr+VXpOM0L53jlW6mgSw5hB/EBhBEMu1AT1cV7RMo5RutNb07B\nM0BkucKFEa60FbGZWKM7llelgmqJPVP4E09qjAaeDrH695v2KBQsnHsWy02S\nFuFOc10nMFw7IyCuppiP/iNjo/ixyC86uH4MGY0Hj0Qc2Qi6pJ4gRohH0NUv\ncrH+zVHRrqRYulE4C7zQDPUFvJz6/wV7R9GRxRgy5oOYhE1xskR661EVO1+e\n6FY3\r\n=jjWx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICAIgyX0+3hVe8KlCtYIzMKKvQ32iVJJY4JIdpjvHwbUAiBh5OE3m6J+laGXoimcbtSNolE65s7+liNoWwy6ASR51g=="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.4_1548854084143_0.919041935638923"},"_hasShrinkwrap":false},"6.1.0-beta.5":{"name":"react-easy-state","version":"6.1.0-beta.5","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":"jest --config ./jest.native.json && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1"},"peerDependencies":{"react":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","del":"^3.0.0","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [Performance](#performance)\n* [Platform support](#platform-support)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => (<button onClick={counter.incr}>{counter.num}</button>))\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => (<div onClick={counter.increment}>{counter.num}</div>))\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => (<Table data={cloneDeep(dataStore.items)} />))\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 'react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  return <button={() => counter.num++}>{counter.num}</div>\n})\n```\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\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 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","gitHead":"957e5a430fdd7e8f2833b08f0551e543decf7eb1","_id":"react-easy-state@6.1.0-beta.5","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-Yce6322TtBc1SE+IAxJOBEGowUrbbenQFZgwozMMT3EvBECoAMKPXmjF704f/pvwos5z0BlTogGG5PZ7snVdSA==","shasum":"a079b120a14b2185403417d0c13542edaff3713e","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.5.tgz","fileCount":12,"unpackedSize":131767,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUaTPCRA9TVsSAnZWagAAgdgP/itSmSbcJ/JzzmCf8cqG\n6yZHz6XETdUhjTzO7qTeT0Q8BpPQ43UNSN52JNiicn4GXuH72Gkq5GTbuEcP\nPG5SIaq2GaAJ6Avz95EuCShyurgDyN4BNWLYQcJ3VFV/3Sgn0BJANFG8w17/\nY2TMNxjF8Iy6mCf4XsNCy0LE9e8qISeTQIVjJ373sKbLJJIu/uGL1PAK6aR+\nbmCAkoWVri6FgEEQs6ADIGeWJMVPxJhjnGZZx+U33NmxheRM0bKAAepAjQwA\nfIaN0GA6QtoE8YEcts5tMD7jlxXbNRE4tiyTgoaX0+WG9tO2JsOjRBO9lqxT\nJ3Zi0zFnLJEG9X9fuWYPn1aV9WBsApzQHhLSpp4P6J92nJUZ7go0AWfWHghn\nNSXyIv7dpnU/uuzLpJJcdDBv8/7bIB0H3Bw2BVciLCMOC365S80FGC6BHYCx\nsh0NKGXKZsIqX2Yp0kA3s/ZBEufrli+ADHnJhsvnse8XwcOrc5xhTi0x6kST\nGsAYa9aodKCRS5pqBH0v+yf4MJdrkH0HX+izGoNqFTLLYTOgnYGSX7ox06iY\n8sVyPLxu+LPxBaAs1hiAlRcc0NgNLKVDEIqlNxZivnf2HWO1D6EGMXMW/yHA\n24LvYlTTdDN0mqQfrOMG3N6hCeNT7257v07BWqpKfdnZuiXfyrzVJ97H7iYs\nh0jc\r\n=oTtW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBVCoZhZeJC6k+g90JgOMDg1GeouTvDk3TNyUYM+vlwxAiAAxbV69OhKIMqLOps+KnsLcf0tDdsXWQsIoNtiFw001w=="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.5_1548854478864_0.06481789457318476"},"_hasShrinkwrap":false},"6.1.0-beta.6":{"name":"react-easy-state","version":"6.1.0-beta.6","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":"jest --config ./jest.native.json && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1","react-dom":"*","react-native":"*"},"peerDependencies":{"react":"^15.0.0","react-dom":"^15.0.0","react-native":"*"},"optionalDependencies":{"react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","del":"^3.0.0","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [Performance](#performance)\n* [Platform support](#platform-support)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => (<button onClick={counter.incr}>{counter.num}</button>))\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => (<div onClick={counter.increment}>{counter.num}</div>))\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => (<Table data={cloneDeep(dataStore.items)} />))\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 'react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  return <button={() => counter.num++}>{counter.num}</div>\n})\n```\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\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 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","gitHead":"53e0e8c977017ca63b4267b0a8bc61f1b0ea273e","_id":"react-easy-state@6.1.0-beta.6","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-wTivBUbyucxPlZNxP+by6PICM3F2BjK+slD8TETeUesvJZl3fQ1QHhvH7z0r1HWdSqfUN5g98cPLwtQ8d3w01g==","shasum":"1d8f6708c381cf82bd1e436c51cafc20d06c716f","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.6.tgz","fileCount":12,"unpackedSize":131905,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUaqYCRA9TVsSAnZWagAAyBQP/R6aW+GAhS2qk0xKX3Uo\nWno9IyJ9/hsD9MR2c77+xsyexomYgVFWIInOFbFDxiT6RV8bPBKepsqdXg0z\n4Gun1F4PUspHFEAjhReNAJMLbAVPnEJvslXrMjaFIZ1pKa6miyX3hkUabD9h\ntD6DPSTsHWs/+EyjVxkfWSDPr+OhPM1FcasTZ/yzjSia06q6/LK5aE0bifbH\nfdvu7wEL1K+EGv0jJBNftEba6/PXSjiS1Qj/ySgPxBroRI30Axf1WtHQBgqj\nYvzSaFAxyBTHzXg3XDbgBEQnt2MelY1pxpJ+0lp2nO3i8Fwz+FIw0C39w578\nSNm2l7VdWVK75DmOkf4VlOh3LLJQ4WwSUSRGQCFZUgwHKLnJF0irnpMuV56w\nBWPLXtRv+7+ZihillrgtHak5K/8EcbCbKfEMkUyPQSlEbniWJEByg4k6N7qx\neW/0gLO4bLMhZ2eTTzc0EoSHvGsYMWzTMunjDfiCWnahuQmjgNYkgjNGN16P\nFav752hDN7QTYhTGzRN/lVsRMaZSAFnuNNPu4CfXnkfgKyxs3mIPdWiZ9Y6j\nit0LH18A0zKht6Cw8zUTKerJEkhGiqHv4j02C0UyGF5gdoF+P5GO01+9Upf0\na+irXeGbf5FPI+b0Jt/HmIb+LD7dFQ8r0eh8VpqrYlY3Xpx3Kt5FsTeJZInO\nIcTT\r\n=f35+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEFdD5psMV6ybzz+aHmNrWWbgAB9WaMO40Rc0BupPiNYAiAbUj1k0W6v2laCv3Pt+JEQTL+cTsw5Iu5wrFLVxgrHqQ=="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.6_1548855959837_0.2207072512912156"},"_hasShrinkwrap":false},"6.1.0-beta.7":{"name":"react-easy-state","version":"6.1.0-beta.7","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":"jest --config ./jest.native.json && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1"},"peerDependencies":{"react":"^15.0.0","react-dom":"^15.0.0","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","del":"^3.0.0","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [Performance](#performance)\n* [Platform support](#platform-support)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => (<button onClick={counter.incr}>{counter.num}</button>))\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => (<div onClick={counter.increment}>{counter.num}</div>))\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => (<Table data={cloneDeep(dataStore.items)} />))\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 'react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  return <button={() => counter.num++}>{counter.num}</div>\n})\n```\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\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 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","gitHead":"af4c4cb8afe962be2011434bb7857159d4f8bf74","_id":"react-easy-state@6.1.0-beta.7","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-sKALhACTS+toUZitWFb21tvrrWeZxn8clDAv13xUslPuh64klO6eqRH7Mw9s+QxeBnCPKOOTxZc2cP/3c4lwow==","shasum":"54589d58b1f19ba31d0a99e131209fef7742d86b","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.7.tgz","fileCount":12,"unpackedSize":131826,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUa7CCRA9TVsSAnZWagAAiKEP/iqQo51ObchoFEpHgoY/\nBiLe901zv/g+sJXnby8J5cKCvuEDvE9KD5lhsKoPQRaRIKbyhNzArWX64hw+\n0kOTek6CJRVYRi5FTQOcG0S/C5uj/oXUvyWHfFLRMom4EIh01VTWvHr0LFw2\neJAnepdFVouTzkZwnINLax1K9+R6MlZNtyo6xKanrEQqitW/nE6/k0UU32/9\nuEn8wrlgTLMqZjP00EOhcU4BfIBygahdyzO1/pJaZToGZx5lo4CP/B11E/Id\nPOrlq/Y91Co+yeAFIMxu66KGngJT1B7S45pwCow7jvM1KmpYfmXZpkKFM47c\ndCBcZO4kXvYxiNCY2JC2QAtivmVAwbEO+uZ3FmHbWqGkNXahInXyqAJjvGNH\nTcHvXQzWalAuw8nVNubKG8Hl6ZlwrTJgvtaLDrFF/ZvZx+rvFv//CSN8G3aO\nH7P/BMnUWMBVtPiO9BjqIbTVcGi1y2UQiQWvnGcO/y56BfAxedugxcD5YrWz\n4OkL0GSDr1uVSYxm/U8cr7wbPXF+Kjwk1btpksfRWIy3/G9wRJL+UHb811qD\nQkH6/SEeHEU/IC1e18CdpFBIUX5PCJXH7o4mMTuFuvYy1FAl7MsWU6kZoUE2\nL2KRH+Ks0K0kiiCuhWvXu3Lz3FXK1LVQGz8QMSAFiR4V+cunshGON88hYSC2\nysyi\r\n=9MFs\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDWbEBbUBF9QDCi1EN4PMhNiamIOHhriOxsU3zJl63PkAIgcJozPuNm2Z7rKkI+c0h/wixYcr9NvXPdoBlxTSBC4bE="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.7_1548857025543_0.13454164416936454"},"_hasShrinkwrap":false},"6.1.0-beta.8":{"name":"react-easy-state","version":"6.1.0-beta.8","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":"jest --config ./jest.native.json && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1"},"peerDependencies":{"react":"*","react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/polyfill":"^7.2.5","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","del":"^3.0.0","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native":"^0.58.3","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [Performance](#performance)\n* [Platform support](#platform-support)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => (<button onClick={counter.incr}>{counter.num}</button>))\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => (<div onClick={counter.increment}>{counter.num}</div>))\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => (<Table data={cloneDeep(dataStore.items)} />))\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 'react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  return <button={() => counter.num++}>{counter.num}</div>\n})\n```\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\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 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)) ([react-native](/examples/native-clock/)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","gitHead":"51cf67cfcff170bd3c5125fc599acd029cddd6fa","_id":"react-easy-state@6.1.0-beta.8","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-JRbyOXAHMMd5kFaggOtrhmUVRkPKgD1Bh5ZyOkhj4LWrW+GcumYt71KBflQ/zdjbJLYGfS7Su6VCkKEOKKWsJg==","shasum":"6bf114f0d4933cebe5c9be1e6bf7ecaec3f2dc7e","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.8.tgz","fileCount":12,"unpackedSize":131981,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUb83CRA9TVsSAnZWagAAMekP/0LeASWwzNXiuRZwS882\n5lGceEkdDaqBHrl8A89AiseNnoUCasylwcQIiNknOM2oQhVETStq8PVkerIU\neEdunk2kGvodJKG6hgurq2LTuL82TemZNoMoW7trqCefWHXw+A0Kyw6U8eu3\nt+0jT0O2lxmq+HgkbkAkNBzKZsVMosTtQW8oZZElxi3UQ9FFEPwUOdIwr9vd\noLizTt++OczdbaHopyU4csLnDUx2qHY0pYXpme9G16M6fD9iDBSKHjTJlYug\niwDqvx0rawoM+RsPlt7W8Xsjs/oY8yR70RRocAuLnpcgJvhCE5Mb5IRFe6IW\n9L7Z8ab91OuiPKOYQVaYeQsZ3VdAlX1KacqoKyXfZ+jgA4qCERehaRgJDGwC\nLUZUQUGE40kGab5+FCw0m7R6YPzZhhcrINSOCtrc160gVd0qC+uEFB/LFu5e\n64yL9deRir46WOV2lv3+yEj24p74qlkVROtRkrP2ZjhQM9El4oauMTNYOF+N\nchZSXwIDuJlXeNqB62+9ciJChCsL/oEWH7V8XDr5Y2xqz999Z0YoTi2Z4Xbj\nTmFA6I4p+3QNWGmdPDVYQrsBqUP757gEj7/6MA0TW5CcprdNAt3ftNrh0nxt\n8ew3F3p3T2jJbk9mB2zicffmxAeQ89auOI8tNVyfD/vColCqN2SzhvfNmQdo\nnDf8\r\n=ohBc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICGJUw2sVLWP74w0as+XMRGBXLuOsrBHcgXRM47NxeBaAiEAkVpZ4P3SMBMxBtn69OCA7d+/k+szcvKl3jPW+cJWAYA="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.8_1548861238478_0.9970154357068228"},"_hasShrinkwrap":false},"6.1.0-beta.9":{"name":"react-easy-state","version":"6.1.0-beta.9","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 && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1"},"peerDependencies":{"react":"*","react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/polyfill":"^7.2.5","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","del":"^3.0.0","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native":"^0.58.3","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-alias":"^1.5.1","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [Performance](#performance)\n* [Platform support](#platform-support)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => (<button onClick={counter.incr}>{counter.num}</button>))\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => (<div onClick={counter.increment}>{counter.num}</div>))\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => (<Table data={cloneDeep(dataStore.items)} />))\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 'react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  return <button={() => counter.num++}>{counter.num}</div>\n})\n```\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\n    </div>\n  )\n})\n```\n\n</details>\n\n**Local stores in functions rely on experimental React hooks. They are not yet supported in React Native and they require React v16.8.0-alpha to work.**\n\n#### Local stores in class components\n\n```jsx\nimport React, { Component } from 'react'\nimport { view, store } from 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)) ([react-native source](/examples/native-clock/)) ([react-native sandbox](https://snack.expo.io/@git/github.com/solkimicreb/react-easy-state:examples/native-clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","gitHead":"354f5ab3eef45efae983033d1323a51dd0ba9df8","_id":"react-easy-state@6.1.0-beta.9","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-Ma/yU2v9q0AkPjTaouYYCAFIODbGUDcZjDNPKIZ5z/ZWnwCIrL7nbqCBFXHkyRjNiwwF/tBASQ+IMfpigWTBdg==","shasum":"f286f7dbed66f389e66611f500988c36f91a3930","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.9.tgz","fileCount":20,"unpackedSize":231592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUdYGCRA9TVsSAnZWagAA7ckP/RlteyLbSMbdZS7bLxwg\nBH8SE75xRBoTbOFKSN2uiKTdKb23btZxqUUgMKHLUiA0y0C9fZZlsskrg89w\nc9TCNPeEKNbR94nSjvGzzcjkBrRR26JBhDASxmJA+H17obt99JtYy6wXLAhR\njyfozrMfKGzThg7vxg7zbuWvLKoWfa8caJvlObWv+lN77nkCFbl6A1gpkQvx\n/cxsLhEpw/LxFtIyf5LFHK9ATsi9wQSQo6aynbJxLLri18mZMcIF59RfkR07\ndlbhr1vAZUplMwQPq0u3NxE72I3SY4BAIqg91a52cUJh5Ua9iLwcfLiS8PCp\ndhukTWw5w8yK7oqUTHcE0Vdsam3p542zqkdAthRNNMxjvbghWM/Ghkbz03iS\nw52eV3/u760+iL78vUkUpJjKzF2CcXPLKWjRBty/BG36n9bGYSDLoU3TQbBq\nasgi05ztDjvmmulsqMnq9Af5G1ByeGbsjKKwP7XT0upGFvTbQNvP4F/nJPth\nMRd9LJHmheluzJQvlkTitcSde/Bf2FDTzVC1Iy9vmpouDRVS/WlGt10LBFH2\noSb6EIVzv+a9HN3/+afBLiVyJ449Db7jhoyq6SpWqVa/gnPonIT4pHpV6J+O\njV+QDQBy8Vzjr1XlpAuzdlL4mZKObQVNSQgvS7gZaAs8wFSXhveXOuHfddDt\ncWfV\r\n=1uTE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEW+e/e9RmDGZ2Mr3/ClJUdkYF5XSxZiAklbSQkYz7upAiEAokgv9SFQkf6/1wlOIaGK0njs58TWp7TxN1LZh1CHJuU="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.9_1548867078071_0.34178419172842034"},"_hasShrinkwrap":false},"6.1.0-beta.10":{"name":"react-easy-state","version":"6.1.0-beta.10","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 && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1"},"peerDependencies":{"react":"*","react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/polyfill":"^7.2.5","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","del":"^3.0.0","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native":"^0.58.3","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-alias":"^1.5.1","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [Performance](#performance)\n* [Platform support](#platform-support)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => (<button onClick={counter.incr}>{counter.num}</button>))\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => (<div onClick={counter.increment}>{counter.num}</div>))\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => (<Table data={cloneDeep(dataStore.items)} />))\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 'react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  return <button={() => counter.num++}>{counter.num}</div>\n})\n```\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\n    </div>\n  )\n})\n```\n\n</details>\n\n**Local stores in functions rely on experimental React hooks. They are not yet supported in React Native and they require React v16.8.0-alpha to work.**\n\n#### Local stores in class components\n\n```jsx\nimport React, { Component } from 'react'\nimport { view, store } from 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)) ([react-native source](/examples/native-clock/)) ([react-native sandbox](https://snack.expo.io/@git/github.com/solkimicreb/react-easy-state:examples/native-clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","gitHead":"354f5ab3eef45efae983033d1323a51dd0ba9df8","_id":"react-easy-state@6.1.0-beta.10","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-KPckqz6MHrGgYgqT58ASOHTIvBoT/sJKHhoYsTEbNg1+sSAns8LC7wsk0wEUrDu+fwHJJERXgNTCFJ7vUbo6bw==","shasum":"b0fced39174c92a652fcc74235129547f67a118c","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.10.tgz","fileCount":22,"unpackedSize":231653,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUds+CRA9TVsSAnZWagAALocP/A9uACO4mHchhv1yWvsa\n0DSfHFCFJ0SRJIjd8+FB4g3hoa9VzrMyfBtlhuvDIXpdpHdmNHexB3jkWEi9\ntQazhgjXmiFrKcWZ/271iVO8iSpPo2dze2hL0HIGZs24WW+2Mtjod+TyIVUT\nNJmJ7wAON8jO4b7eAKZXUhUTvlFzcPIXIzjwqrstFYS1Pz60Bl1Ihg2jHEgr\njTPmXJE9nTJQWnIyvV2lHF3Vul2kToddcLZyUtdmVgc021XIulJjFj5ulWG4\nl3zS0RP2C+JcrgJY2yprrCdzT47w01BzYmVqVpq6+xPsxdsu1WXAi/Hmmfbs\nkSfd7jA33We9JLBgjFehAM47YsFuq7ALrb2YTNuYwZXg5DdN34y4iBfg7BhR\nsfG6GDJb0a9nMGTreA0+PqYtAw+FMgDa0BV/iLu1OIBXwk0hwnSYZ3ghCq/p\nypNVB/MTobTGEcHVC9hGXJVK55rwXvbvDtuR9J+L2TbVwCNzicdce5ughkVc\n0ypD5KZ4vfAPleY817NMb9pY5V/XHLPZxwGico1l7uYENi28cUe/AeVNqjnu\n/PGxoPxzmdHU6bkHBAgksDqSEzHNELBVAyUKh7FsgyqPajbX5lhh6/4Lbnmt\n0aSfOmnyK002dyFLgSUiPohmJFKDXyhhoWFYJyTDAHrp+5giV0d8ffqXDo6m\nrEYq\r\n=prFK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD8ts2/NIWD+gl3Gka4okek29JauWYGTfQM5MOBXH8kTQIgEpcprBTvB3k1fnSGOqgnivBJkMFq6GzKgdBAhLdUcbo="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.10_1548868413582_0.31814509880878483"},"_hasShrinkwrap":false},"6.1.0-beta.11":{"name":"react-easy-state","version":"6.1.0-beta.11","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 && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1"},"peerDependencies":{"react":"*","react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/polyfill":"^7.2.5","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","del":"^3.0.0","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native":"^0.58.3","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-alias":"^1.5.1","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [Performance](#performance)\n* [Platform support](#platform-support)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => (<button onClick={counter.incr}>{counter.num}</button>))\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => (<div onClick={counter.increment}>{counter.num}</div>))\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => (<Table data={cloneDeep(dataStore.items)} />))\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 'react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  return <button={() => counter.num++}>{counter.num}</div>\n})\n```\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\n    </div>\n  )\n})\n```\n\n</details>\n\n**Local stores in functions rely on experimental React hooks. They are not yet supported in React Native and they require React v16.8.0-alpha to work.**\n\n#### Local stores in class components\n\n```jsx\nimport React, { Component } from 'react'\nimport { view, store } from 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)) ([react-native source](/examples/native-clock/)) ([react-native sandbox](https://snack.expo.io/@git/github.com/solkimicreb/react-easy-state:examples/native-clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","gitHead":"354f5ab3eef45efae983033d1323a51dd0ba9df8","_id":"react-easy-state@6.1.0-beta.11","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-6Pou/k6XdYQ9s1M5dik8COsKrC/djyK2GP9c8CQytUfQm5Pw5K1fEwjFdhr27S0Ww9kT0abgQGBn+Pno4/D5+g==","shasum":"8baa83f1ce78c89e1cfd46a912ceb84fdbefd3d4","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.11.tgz","fileCount":22,"unpackedSize":231656,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUdy5CRA9TVsSAnZWagAAfI8P/2BckWzWO7n4ur1djbJ2\nlQ4+egS3CI5HsvaeKAZUZiVXdk6txQEt3Yd2Sx8U5e8shnMScHbc12lYVysF\nX8ddkGDoyv2dmmXF3dNvDRH7K5W8tPAbIgANo68QPhM7gt76+0cAAYuXo/5B\nKEkOBAAuLuysCUWzx8asPv0Z/bxRMF0jzwmEZiyTDK4uRhbggKqYF5vyHtSa\nHPD41283cwHBCMLKOdiQBG1O6KdRwuiiETDjolpxCkM40V/mKGGJj0iphCs+\nOLHUhQtbsz1nEj3i9I/Gsy7/uXKdoWNuEKLHxHFiQYHXo6LYweAcUgd0u4y8\nsN+ZS9VaSKk1/TpB3U5Y01NvIW36zpKQDP5jyaKbkdBpNcubOzYWr0TT4Q+8\nEkbS6nlF89R7DMphUEfjSLFuw6ls3Qizws9mxhG48SLJarcT/Xwezqyhceao\nkdl5FB7ebugNwyPsU8TKzPzIMs40oZmuQb9i3ltMuH609CM3y2nHuFJ93mCs\n4XlqN2fIavTa6feiHXQbRxLM80j6L5KifdVWqaXVQk0RrF1UBDyMQHcCjRsz\nkBAOiSYJFKW/sVuoQw7L4xKqxVZktqV3QkSInXtCWq2b+5PhhOVrUIArTXaB\nupOf3dyA/yRPmDnk/oTMmYr8zh3JHZBps2AE6tMLCNGYsE2v8q3GRdB79X5N\nCN/L\r\n=Amz3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAVyrI4K5JVRvEBcV9XCbBDHVLoyz+xmPZ8fB4jPx9DUAiB19VA21gDjQCf7ebPdx+H/8XdcKhI0QW2Y4Er2QkyO6w=="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.11_1548868793167_0.9308230094556147"},"_hasShrinkwrap":false},"6.1.0-beta.12":{"name":"react-easy-state","version":"6.1.0-beta.12","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 && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1"},"peerDependencies":{"react":"*","react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/polyfill":"^7.2.5","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","del":"^3.0.0","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native":"^0.58.3","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-alias":"^1.5.1","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"354f5ab3eef45efae983033d1323a51dd0ba9df8","readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [Performance](#performance)\n* [Platform support](#platform-support)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => (<button onClick={counter.incr}>{counter.num}</button>))\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => (<div onClick={counter.increment}>{counter.num}</div>))\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => (<Table data={cloneDeep(dataStore.items)} />))\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 'react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  return <button={() => counter.num++}>{counter.num}</div>\n})\n```\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\n    </div>\n  )\n})\n```\n\n</details>\n\n**Local stores in functions rely on experimental React hooks. They are not yet supported in React Native and they require React v16.8.0-alpha to work.**\n\n#### Local stores in class components\n\n```jsx\nimport React, { Component } from 'react'\nimport { view, store } from 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)) ([react-native source](/examples/native-clock/)) ([react-native sandbox](https://snack.expo.io/@git/github.com/solkimicreb/react-easy-state:examples/native-clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","_id":"react-easy-state@6.1.0-beta.12","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-MhFXFsvB5N1EwvsZ50dyfD02ez2HQM6oe3iTJewVq7uAXpYtAMOHzbc9JFJHszUSnndGDL7ET7nxzLinH41fFA==","shasum":"a9ccf532afa4ee0182eadbbf29a1681ce20595de","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.12.tgz","fileCount":24,"unpackedSize":231740,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUd1ACRA9TVsSAnZWagAAWGYP/027Rfz5MkPhcG0AGqBG\nDeWHBXU6H++5vbN6h7tbf9Ok34fuoHkMokY2BUCfv7T1Je4WgPLg2sgjUsFK\nltPWtB5HzOkzzx7UY1AFBnKtTpG9Eu8DhBuAFuOe3+CTEJmGswYQtbBYqP7B\n4M5R61AvA6eMQRtaKwZWr+Hl1rtN7Rr/ycISYoXo8BMRTDMgEpKHkXiYVGVJ\n5ba5B3jhIXcBzFaOnxaXyp4aiBDLtN8inY2ZJsDCsQ5SYBxP/6VLS2H6fjQt\nhknjj8Yh2UU5ocPq/IBZUl0Hg9XCC/NNZsibT8z7zFfH96+aW4rfePJiuDTe\nIkhU9cQowPoDu07AcO5r80YYntmHRSpP+sr5cHtbQkF2f/1/Oh93biAdLff5\nVA83FWxs5Jo1Kk+RZ87ctkI+2g3BldHwrai7wmFiBaWFE6tDvlxTcdwYN1MZ\nJb0PSsLzqi/Yz7fe6CQVwM/fvbEq7oEIihXR/5uPXgT3S6+hp9Rj+xUzdp7Q\n6dzioT85xb4txkP8n0mwBmfCm2O8fjuitQ/bB/Te+9EQFkdkerBXqEq0uU0L\ndu2ke1Q0pGf4dvUiUQ5YHfys02yiFDXeM7IIuVhpUgz0u7lpKv+a2wmlsbpa\nF1eoB6BwTGmjTP3y2fB1rf3yAASVp9zIRPNePeSWs9LhYarV3lD/5V8JTZGW\nBbFS\r\n=G2a7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQChZdiEO6KMMaGk5CoixZbqete6hTHPFUPi/ialNfTfIgIhAKw5b2At66gbIeLUyLhLgZ4FC+Q3qUdGSQiWOJ2vNLQ8"}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.12_1548868927826_0.4242105781822618"},"_hasShrinkwrap":false},"6.1.0-beta.13":{"name":"react-easy-state","version":"6.1.0-beta.13","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 && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"rm -rf dist && mkdir dist && cp -R platforms/. dist/ && node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1"},"peerDependencies":{"react":"*","react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/polyfill":"^7.2.5","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native":"^0.58.3","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","rollup-plugin-replace":"^2.1.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [Performance](#performance)\n* [Platform support](#platform-support)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => (<button onClick={counter.incr}>{counter.num}</button>))\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => (<div onClick={counter.increment}>{counter.num}</div>))\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => (<Table data={cloneDeep(dataStore.items)} />))\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 'react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  return <button={() => counter.num++}>{counter.num}</div>\n})\n```\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\n    </div>\n  )\n})\n```\n\n</details>\n\n**Local stores in functions rely on experimental React hooks. They are not yet supported in React Native and they require React v16.8.0-alpha to work.**\n\n#### Local stores in class components\n\n```jsx\nimport React, { Component } from 'react'\nimport { view, store } from 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)) ([react-native source](/examples/native-clock/)) ([react-native sandbox](https://snack.expo.io/@git/github.com/solkimicreb/react-easy-state:examples/native-clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","gitHead":"0c7feebd447f3d936e6f4c74b8d8611cf9acd7fe","_id":"react-easy-state@6.1.0-beta.13","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-HgY5lLMpcnB4d6X8eN8AeDCAXF5nT+OARnLMvbbAAL8fyKDrDLurHm4QwJjp//mQ5MgM8qYnK8wEznNABbn9jw==","shasum":"578cca84b8d812f2984653ace7e87b5847ff6f84","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.13.tgz","fileCount":16,"unpackedSize":129172,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUesKCRA9TVsSAnZWagAAe4kQAJx2RQn2MUZSMZdoGlQE\nprKmmTXWL9huNCTtLVMe6Z6xpMxWfuQKB2AVXbcYERtoY2ywC1hd4Z/uKOgJ\nbqMjoPRSlO+W/cf4F9pkqUq+xnNQpcNGWE4zyzRsYPWyOSAXVwmtk0u395B+\nLimM/+fLoreXTDbSdaEmG9ag3pFST1I7gxMt2LO+qcnzaR/5Sv8UgY7pqZdY\nCZIlRfr+FNMZtiIjiwKXATFS7YObk7Z93oiDf9TLJarX3GhcTrfnEtRWq/2h\nOwb4wM6hRIklln0yNWCotGrVZzrTAnqisGgxvp939wdfrI1LS/gxycEMLaEb\n3uPwHYTuNnVmEMETnxo3s0d/VI8Auscr/v04jmRI/6YfpVh/elhkMgYWz3Ab\nZQZlFd6x1/piJE6/4hoUq1a1YGCYZ51IOIljpzl+Y0NqnsFNpzHKsxBihl0N\nTXL7IDjGZt0DVagcLEV+X5FO3HBqJunyMhGTKvR/F7VYRTnyU5fofEUJyZLu\nmL9i6vwQRaz7S3PvGnCozC2hyraHlJiT6WIbNmzuKa+EgfchOhDi7ZTdD3mr\ndDEoT5HBFpR8OvjJo+DfdkszXahudA3os5jZScY9e0x98S7g+paHnB/mar7V\nVlUzhnHtEv1MAdVMUhmW3ffUkMoAGu3FRYZ/yyHE+rJJcXR/UjvNowVk2Df1\nPwMe\r\n=yxgl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHXvKHFSR+vrgaqIMIolFJ/TidJ6rnrsL7LuyYp2/lfBAiAIJsdj11cu3RB9iIRPYjqjxSmyCtfcIk0MllVevE5Tsw=="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.13_1548872458045_0.3466746234177678"},"_hasShrinkwrap":false},"6.1.0-beta.14":{"name":"react-easy-state","version":"6.1.0-beta.14","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 && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"rm -rf dist && mkdir dist && cp -R platforms/. dist/ && node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1"},"peerDependencies":{"react":"*","react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/polyfill":"^7.2.5","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native":"^0.58.3","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","rollup-plugin-replace":"^2.1.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg)](https://coveralls.io/github/solkimicreb/react-easy-state) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n* [Installation](#installation)\n* [Usage](#usage)\n  + [Creating global stores](#creating-global-stores)\n  + [Creating reactive views](#creating-reactive-views)\n  + [Creating local stores](#creating-local-stores)\n* [Examples with live demos](#examples-with-live-demos)\n* [Articles](#articles)\n* [Performance](#performance)\n* [Platform support](#platform-support)\n* [Alternative builds](#alternative-builds)\n* [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({\n  num: 0,\n  incr: () => counter.num++\n})\n\nexport default view(() => (<button onClick={counter.incr}>{counter.num}</button>))\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 'react-easy-state'\n\nconst user = store({\n  name: 'Rick'\n})\n\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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => (<div onClick={counter.increment}>{counter.num}</div>))\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => (<Table data={cloneDeep(dataStore.items)} />))\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 'react-easy-state'\n\nexport default view(() => {\n  const counter = store({ num: 0 })\n  return <button={() => counter.num++}>{counter.num}</div>\n})\n```\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\n    </div>\n  )\n})\n```\n\n</details>\n\n**Local stores in functions rely on experimental React hooks. They are not yet supported in React Native and they require React v16.8.0-alpha to work.**\n\n#### Local stores in class components\n\n```jsx\nimport React, { Component } from 'react'\nimport { view, store } from 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n* [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)) ([react-native source](/examples/native-clock/)) ([react-native sandbox](https://snack.expo.io/@git/github.com/solkimicreb/react-easy-state:examples/native-clock)): a reusable clock widget with a tiny local state store.\n* [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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* [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n* [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n* IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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* `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n* `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n* `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n* `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","gitHead":"64c8af22c19df52c16deadbcf060df1257ae67db","_id":"react-easy-state@6.1.0-beta.14","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-ayMVdS4/qZqVzeIbMMUk+UexvV9U1q+Qo3cky+ya78vnMJy9htUirjfbRwUNd08vCBR/gfUv4L6H9vdjpkbk0w==","shasum":"1ace76e8112b042b2c0a655ceff9810e2e7604a7","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0-beta.14.tgz","fileCount":16,"unpackedSize":129214,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUe98CRA9TVsSAnZWagAAUzwQAJKBjv6uqCn6kFUvAxpc\nRxLTdqbl+gw3IIWcRLTPdzmcCAjvxCx8PGi8OnMXAsPgUtVOXVB4eKcb3ESS\nrNQQ07ZmUadKHVFX9icvgjvxpZ1FYbTrDoNojs1ykzlACjwJS1v7KIzCQGPj\n/p+sgzOIdSqgyZaLpMRgYIAvAlm38ZHyiUQ/WVt/N3pYgmMwpap5O8HbEv+v\nUzyawJ2HDAC2FZAZqGk26RG8XE4T7+VHYApmKKHwLmeuc12AaIXkYFgkuuhR\nKTddSH2oxod7hZ98uk/pzrrx672M6T7SQh7zshzo/QL41+goHmNbW8sDU83I\nXyNeOWJI6BCpAeywNHBveNmq5+XkvOAjcdvQCJ93wifdSxsxWkBnEXiG5Mg2\nfCmUCvpGswvNlZPAhRSYXu70WNOaJsZfKl+O/WMumX/GGT6keBw71GOCTX90\nEMgAkQhLzZAA4Ajz9z7bKZrfUJ2zqdv8R+0DaUVJ8P9+BrHdZsWMQfWAHQ1f\n9AZLENChgO9ajwe2pFJRrBJl8IWYIrN/rvMbbKCLN4Ur4z0NzHt675ZXDk7y\nGMXKwN7Zo5EpgY7ydPUybjg5IBXmVRlZzIV41I4zOuOTSVs6o7Deu4nEB8W1\nT6+1U7AMCNlDRzuQlefMd2OiEfsTs0zhC9bokfli33pu9vY14TbzAXtQMr63\nqBra\r\n=X+Q8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD+PZX+2cIYni+UpUdzrYlmDWSHy3Eb3YUHzG4MiQshQQIgY9vJQ0jpZ/If+b3FtX4BKqsH5Qf4X4Z9MRFJyAcKl1M="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0-beta.14_1548873596224_0.3006805009473952"},"_hasShrinkwrap":false},"6.1.0":{"name":"react-easy-state","version":"6.1.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 && mv coverage/coverage-final.json coverage/coverage-native.json","test-web":"jest --config ./jest.web.json && mv coverage/coverage-final.json coverage/coverage-web.json","test":"npm run test-web && npm run test-native && npm run coverage","coverage":"nyc report --reporter=lcov --reporter=text --temp-dir=./coverage","coveralls":"cat ./coverage/lcov.info | ./node_modules/.bin/coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"rm -rf dist && mkdir dist && cp -R platforms/. dist/ && node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1"},"peerDependencies":{"react":"*","react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/polyfill":"^7.2.5","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0-alpha.1","react-dom":"^16.8.0-alpha.1","react-native":"^0.58.3","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0-alpha.1","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","rollup-plugin-replace":"^2.1.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"e41a4567e1172e72fd95f35b510a28b7d16190cd","_id":"react-easy-state@6.1.0","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-lSJbrNddRYzpVysLzJNANWKMtlsPj3B2EQ4s8TDv0tc/J2wfDm3UGPlK/BsdQuIrF6m4yEigBvi6nAufy6MI4A==","shasum":"0ed46e053a9e5f934164231a54cc11b71d2f596a","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.0.tgz","fileCount":16,"unpackedSize":129208,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcUvEICRA9TVsSAnZWagAA6FoP/0Zu2zv74D2uG9Cl4daT\nKMqMj0wCPSI1a1ckLoeaKLVxoxMMkzm/UHLTuaGy520HXuW5+WDS+6yyZnCs\ngXGMlUujZr4+Er9POC2NPqqjl0O+T5O6lwVsHwWheoPRGrnnWGYb1GojqNWL\nRFq4kEwS41dCiu/p7QSLOQZRnhh/6sxxFmhRtm1eA0rXYt9+CKpZxVLhxbP9\n2q5UI1VK2eNeAoTZhISOht0QqDN1sFG9nyw8twnNpfewA3HyxSaNx7WdLURb\nGPdUWiaxsFU8/w2NFF9qO5Q7U96uSHDhb1jP4A3mXsQVO43ozHoXOWp/Wns6\nqAPwQ1vCyNGdYWrxJqashHzaCY9YXXfv5KIC4uwcj1fpCE5LeQStlJfnG/Yi\nx9B+XoIi1f2kBA0x6bopnyFNjhVXyaqDOD4xX1JkQkLLr1IoYwA6yvcU4SRU\nJFsd/dIgisNyA8R0ihsMMIv0w2RmIvS0SpmUcQcj+tkzCnjsChOeBYhTdk54\nuBB6s8jvIWg44K307nAL3676Xh9V7yE6jx3hLKjs1zrSE402LuyY1RTiG8tz\nEyclyhrrsgCLjLzaBfO+6RhO8v/GQDl0GRwZvaURttnCe8+GwozK0lF0YNb5\nfOML1OHpX0vL34YZ99gbToo9+An0yTbQm/sUnLVSBE+memalFDxZvxtJzsZS\nsE1l\r\n=TqlY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG+Io0Dl+Wsd2dnen4oJs8X1BgA/5YVxg+bco3h6qbzEAiB0XQ0/BiM9AmrsNux+r3s70LwD7R7KJqGSjXSC8a2Q6w=="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.0_1548939527171_0.2978289366332132"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"6.1.1-beta.1":{"name":"react-easy-state","version":"6.1.1-beta.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","test-web":"jest --config ./jest.web.json","test":"npm run test-web && npm run test-native","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"rm -rf dist && mkdir dist && cp -R platforms/. dist/ && node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1"},"peerDependencies":{"react":"*","react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/polyfill":"^7.2.5","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0","react-dom":"^16.8.0","react-native":"^0.58.3","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","rollup-plugin-replace":"^2.1.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg?branch=master&service=github)](https://coveralls.io/github/solkimicreb/react-easy-state?branch=master) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Simple%20React%20state%20management.%20Made%20with%20%E2%9D%A4%EF%B8%8F%20and%20ES6%20Proxies.&url=https://github.com/solkimicreb/react-easy-state&hashtags=reactjs,webdev,javascript)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Creating global stores](#creating-global-stores)\n  - [Creating reactive views](#creating-reactive-views)\n  - [Creating local stores](#creating-local-stores)\n- [Examples with live demos](#examples-with-live-demos)\n- [Articles](#articles)\n- [Performance](#performance)\n- [Platform support](#platform-support)\n- [Alternative builds](#alternative-builds)\n- [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({ num: 0 })\nconst increment = () => counter.num++\n\nexport default view(() => <button onClick={increment}>{counter.num}</button>)\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 '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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => <div onClick={counter.increment}>{counter.num}</div>)\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => <Table data={cloneDeep(dataStore.items)} />)\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 '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 experimental React hooks. They are not yet supported in React Native and they require React v16.8.0 (alpha) to work.**\n\n<details>\n<summary>You can use any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\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 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n- [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)) ([react-native source](/examples/native-clock/)) ([react-native sandbox](https://snack.expo.io/@git/github.com/solkimicreb/react-easy-state:examples/native-clock)): a reusable clock widget with a tiny local state store.\n- [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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- [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n- [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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: iOS 10 and above and Android with [community JSC](https://github.com/SoftwareMansion/jsc-android-buildscripts)\n- IE is not supported and never will be\n\n_This library is based on non polyfillable ES6 Proxies. Because of this, it will never support IE._\n\n_React Native is supported on iOS and Android is supported with the community JavaScriptCore. Learn how to set it up [here](https://github.com/SoftwareMansion/jsc-android-buildscripts#how-to-use-it-with-my-react-native-app). It is pretty simple._\n\n## Alternative builds\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- `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n- `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n- `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n- `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","gitHead":"3c1e285b3421bcf40534e6cba03d2096fa74085e","_id":"react-easy-state@6.1.1-beta.1","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-C3u2nWJKjErCCtrSYmMLNOd6PNLts8/oMmwiEd3hWiZSoHHMTwIlBm4KjIenLC/8u2Qw+FHPC4qQ8m8OBJhKNg==","shasum":"acb2145b4e01689904a97306d44477f3d055a39c","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.1-beta.1.tgz","fileCount":16,"unpackedSize":128945,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcWq7qCRA9TVsSAnZWagAAUaIP/0GAp0EpFrbImpPzxQap\nrdr1o9NpjS27KZNcx8CQvoiGJEwny3sIoezarJvVY0e5lrhZasqGoaQzpQno\nBlVcmO+HPfhHXjRFKjLp3bMK+RK7oOpEay5IihtUQoYhK8Sbp6WBnO1BjRTm\nAluzvB4QVs1YzpiqdAVSdcO0YE5vq1iGoxBWRNkYOGL2EI1TKxtfFcPG5RKs\nCWRZ5wQVzlzhxiZpYgsWEQMeWkQ04wc1rlDw/dLtf175tMqqvuY24PVoYWss\nPXfeZEFKqR7wwsRHKc6dkYqbDKL77A0fXEcHEwIza9W1yEmyZVSQ4lrpP6Ij\njkokw4ZDF66tWKYadgz19Pm1fX8ZjRQCo1j7h9giX8XoSTQ9O8oo6OUhfnLW\n/5VfhCb9UKpOHRYKfCO0l6e9qFc76PQDyCc9VDXVIwBOrUGwWCkov2ZqqzNC\nrZ6yrCYs+tVFCLdRXro4r8kq3HjMfJmo5RxdHnpUU1w+Emnsk/EZKgW7WZE9\nncS0vsFKA3XrQ4mbbYixap7SEdteDMLfzUcu5DpVBWXt3ZPNVpAxbq3pa6qd\nLsGMsh56R6iAcqvEO/U4k31Au9r27KOQq1mBb9tOlYI0aEg7udoIWCLiI+Wc\npSnmwYcFgHgS8buHlnSMKUAmPll3m/PCa1QM4JnAXTHQKjlNuGURzRPCw04+\nVuEw\r\n=AjwG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCTDBg2s/OidbHTVhfbjTKtDSyJU532Z37Fp7xvR6AWkAIhAPQ37aYVnal8FQbWQlOzzmP/nWkAXDAyq9VHjcF2o63X"}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.1-beta.1_1549446889970_0.3709533393200153"},"_hasShrinkwrap":false},"6.1.1":{"name":"react-easy-state","version":"6.1.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","test-web":"jest --config ./jest.web.json","test":"npm run test-web && npm run test-native","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"rm -rf dist && mkdir dist && cp -R platforms/. dist/ && node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.1"},"peerDependencies":{"react":"*","react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.2.0","@babel/plugin-transform-modules-commonjs":"^7.2.0","@babel/polyfill":"^7.2.5","@babel/preset-env":"^7.3.1","@babel/preset-react":"^7.0.0","@types/react":"^16.7.22","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.2","jest":"^24.0.0","jest-dom":"^3.0.1","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^13.1.0","pre-push":"0.1.1","prettier":"^1.16.1","react":"^16.8.0","react-dom":"^16.8.0","react-native":"^0.58.3","react-native-testing-library":"^1.5.0","react-router-dom":"^4.3.1","react-test-renderer":"^16.8.0","react-testing-library":"^5.4.4","rollup":"^1.1.2","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^4.0.0","rollup-plugin-replace":"^2.1.0","sinon":"^7.2.3","standard":"^12.0.1","styled-components":"^4.1.3"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"3c1e285b3421bcf40534e6cba03d2096fa74085e","_id":"react-easy-state@6.1.1","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-ELT6/wfJf4HgkikJmTarPi+ebRh4WzfBMZbpYEXfw71ZhMzy+tf8Cz/lEdRk8UWlV+goi50Ie3xazNOuN+RnCg==","shasum":"29a1abcda4566d305fb2312c7ca7cb147ca879cd","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.1.tgz","fileCount":16,"unpackedSize":129225,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcWrNuCRA9TVsSAnZWagAAR94P/jlvQulZDjgeLdmUzGeW\nshSSHiOPy3NZYd1qStw+zpWtx6FEL2GBy1W1VXp2h+CM9DRwUEJwXXkJ8c46\nWLEOAbf5dtOS9ViXim2RyGqf5FqxAu6e41Yz/0M8+abMZyqFbbbSnRyNE075\n2Jhz4W9peCiPdLJTZczQ37wXF4zw2GSHzU1L0O11XBcObEJGE+fzr2GbLlK+\nnC4VYwdm6TdPIROG1CIrLrRcVNeWr3T13SpQ56XuCQB5F5AO/JV+Z42d6fTK\nRiNxte+wKwIb+TTacxewA+RmAq6evMQaOgjPK1hi75FEGof5tMaheCsAQKwp\nra2xONj1tl4nOejPQUuEEGtC3vnTYxSrYeThA410FkmccGd2HWDDKAv8LkN6\n1s82cJHe61Bl/eQqEn+PM1AxVQjgj6NWh2bb47YJOA2oI4vKNxQdtA1jJhIm\njf4J2j2avFqd2TNO94aPtVFHIF+v9xMVIvftMIkQA86YrdE6zwPo1D+3099o\nDXg/VayLPgGhCjQS/3CqN246BwRIYXip8XN6dsrs9l997jQNq5P2nDV/qkyx\nVZ7EfnGjBXidgM/20GOZkRyWXbIb6/Gy9vdTrBPMQg2eK82QUuwNXVsEBgno\n6bFBGOF0EYMa6eqaHsWe7kNGKDnuuiDG07pm2/kq07X1vUSDsZf7aTJoxo6r\nA7X6\r\n=TTVQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAPNVsFTXQGcQS1WVPLQC9iTGjsbCv0GqxFVarZVnRejAiAhhi3Q9+xXGw0DyxfmMF6/pccReh/v/EZ7QfMp/sv6UA=="}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.1_1549448045383_0.8842057513759516"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"6.1.2":{"name":"react-easy-state","version":"6.1.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","test-web":"jest --config ./jest.web.json","test":"npm run test-web && npm run test-native","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"rm -rf dist && mkdir dist && cp -R platforms/. dist/ && node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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":"*","react-dom":"*","react-native":"*"},"devDependencies":{"@babel/core":"^7.4.5","@babel/plugin-proposal-class-properties":"^7.4.4","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.4.4","@babel/plugin-transform-modules-commonjs":"^7.4.4","@babel/polyfill":"^7.4.4","@babel/preset-env":"^7.4.5","@babel/preset-react":"^7.0.0","@types/react":"^16.8.18","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.3","jest":"^24.8.0","jest-dom":"^3.2.2","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^14.1.1","pre-push":"0.1.1","prettier":"^1.17.1","react":"^16.8.6","react-dom":"^16.8.6","react-native":"^0.59.8","react-native-testing-library":"^1.7.0","react-router-dom":"^5.0.0","react-test-renderer":"^16.8.6","react-testing-library":"^7.0.1","rollup":"^1.12.3","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^5.0.0","rollup-plugin-replace":"^2.2.0","sinon":"^7.3.2","standard":"^12.0.1","styled-components":"^4.2.0"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"1aeb0ddbc386a36adc3758a12d740989e99655a6","_id":"react-easy-state@6.1.2","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-D7lLTT8JVHvr7K6HXKyMgqfE4ry7t9Sptxc5IKcgmbABTTuWA0hYD8IVyYDVtOMnQpcCmfGdYoSl/8m+CTSzpw==","shasum":"20c69133a2fbba531565bf034c75808e1886bcc4","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.2.tgz","fileCount":16,"unpackedSize":127268,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJc5Xd7CRA9TVsSAnZWagAAprwP/RX0fJrh2nyIk1a+xsF+\neM5HuA+cBTOhYJfd4WBvjmFXC/S6O+n++q+VVpH+UJs63fVwLS7bQqRr4UXE\nDxysUWwIR0Kl7XOhkMy6UQnKEcprSN1A2om278GooywaX9dLYU+TqbBVq0Hv\niWgrbZoh7FBIc3ThKs9oUL299DTfKoFSIYI4mxeMhPKEvMJsiXTu3rzdtOer\nhQYyn3hdJekPjr9BD7YIYi9kWKe0zdlkSbqnvc9u+zf99dWjVKb8I27hQDpG\nNL6h7hRrfsFQq+BnObjvuYG62zzEwHr2sxZFM5OQI8xb0H7GZhdnAnntk/Kn\ndy0lI/EnvTv+JkSQSDMnVu2ZkAmgwPh2YiUoEvoLr+jTYu66g7rbI1BU64J1\n/RxXkwBeGctt1nwO40XNmXlcaZKln6uiRSg9tqBNdy7vwwT2127ETf2xji7H\n9INwPtw26GGz7lnj9tNjbQwK7qJIW3s4r7dimvqs0y78YRzjnVpd46PmfRny\n4zt+FBZ9F2VPriL/BI+8SzD6AmykaAzkLEwERALtpQGiavY3FnTAxjqi+crd\nPskGiDQNnrFFAjq/uPNxZ5WCJygRH9cuOI4KwvV8hRaXoOqSCtOmMt5JvvJ5\nktNikXk09CRrVk7T8I7pltPdsGqj5hU7Hi4cWk7IePdGsSGc7KLIRi64rkLq\nSwUx\r\n=70im\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDBnSIahUW6GgY4VDLz+hPJlEJRKeQ4+tPe3uLZZLO+WwIhAMthAASpD4/kMNHM65moMOUrNzA72N1E4JnPaGtK+bQb"}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.2_1558542203012_0.14062505861127317"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."},"6.1.3":{"name":"react-easy-state","version":"6.1.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","test-web":"jest --config ./jest.web.json","test":"npm run test-web && npm run test-native","coveralls":"cat ./coverage/lcov.info | coveralls","test-builds":"node ./scripts/testBuilds.js","lint":"standard","lint-fix":"prettier --ignore-path '.gitignore' --write '**/*.{js,jsx}' '!**/build/**' && standard --fix","install-examples":"node ./scripts/installExamples.js","build-examples":"node ./scripts/buildExamples.js","link-examples":"node ./scripts/linkExamples.js","unlink-examples":"node ./scripts/unlinkExamples.js","build":"rm -rf dist && mkdir dist && cp -R platforms/. dist/ && node ./scripts/build.js","build-toc":"node ./scripts/buildToc.js"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"repository":{"type":"git","url":"git+ssh://git@github.com/solkimicreb/react-easy-state.git"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"homepage":"https://github.com/solkimicreb/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.4.5","@babel/plugin-proposal-class-properties":"^7.4.4","@babel/plugin-proposal-export-default-from":"^7.2.0","@babel/plugin-transform-async-to-generator":"^7.4.4","@babel/plugin-transform-modules-commonjs":"^7.4.4","@babel/polyfill":"^7.4.4","@babel/preset-env":"^7.4.5","@babel/preset-react":"^7.0.0","@types/react":"^16.8.18","babel-eslint":"^10.0.1","classnames":"2.2.6","coveralls":"^3.0.3","jest":"^24.8.0","jest-dom":"^3.2.2","markdown-toc":"^1.2.0","moment":"2.24.0","nyc":"^14.1.1","pre-push":"0.1.1","prettier":"^1.17.1","react":"^16.8.6","react-dom":"^16.8.6","react-native":"^0.59.8","react-native-testing-library":"^1.7.0","react-router-dom":"^5.0.0","react-test-renderer":"^16.8.6","react-testing-library":"^7.0.1","rollup":"^1.12.3","rollup-plugin-auto-external":"^2.0.0","rollup-plugin-babel":"^4.3.2","rollup-plugin-node-resolve":"^5.0.0","rollup-plugin-replace":"^2.2.0","sinon":"^7.3.2","standard":"^12.0.1","styled-components":"^4.2.0"},"engines":{"node":">=6.0.0"},"standard":{"parser":"babel-eslint","env":["browser","jest"],"ignore":["**/build/**","**/node_modules/**"]},"pre-push":["lint","test"],"gitHead":"ec82885180db764efbb40e72ed16f377dc944674","_id":"react-easy-state@6.1.3","_npmVersion":"6.2.0","_nodeVersion":"10.7.0","_npmUser":{"name":"solkimicreb","email":"miklos.bertalan@risingstack.com"},"dist":{"integrity":"sha512-uWQ7ittvJylwn/Xgz7Ub1jjsbpthQ9Ad1KDLxXfbXCb2OPnov4porVdnOJU2PKeRezcam3ZgfPUtf9L9rjtyWg==","shasum":"f9db4e8d842b5acfb73b6899aaf49a26900f7d26","tarball":"https://registry.npmjs.org/react-easy-state/-/react-easy-state-6.1.3.tgz","fileCount":16,"unpackedSize":127941,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJc5uyOCRA9TVsSAnZWagAAP/oP/jR5p/fJIz1s2njcaYRV\noAC/aFk62tgB6+cly00RWluoa5QVTFwYNOyaENGSO1NhAmOh3gsbsqtrGHiM\npHVs5UTtBOxOkBFF7vjxD1mBmoNmtKckBeZL+x9wT0JQsaBj4VwOJ54x2ZAy\nEVDRgZNGbrKIU0Iznkhsj6ljVoxmZyJD6RQOfoU+FlHNAV1ASAcnCLLKkTwh\nBd9Q2GrZxC0pR/kAPnsNb67f3Eg/UIGgu5mHu1mk2E59iRe9zHJ/aS4zvj13\nlbe/OU3rhvqPktEsZEacmamngwL609z7B0hS2gAKRqO36EcTzLdWDpNDS+m1\nNBlPFrqJ6EToIQ432nku7qvJLtNXtvjUjL6zdPmAxFQoidetP9NLj4VMLUXC\nAtncg/+0G1NExESV7SDEYkOah7VPWRMzkY80OkkgDOKNmlO0v+gFuwh0caxa\n+74WoJ7jDmPEIdnwtIGR7xZCi+pjAeCOpVWbGlCrrbYKsawWyeCa6umXtI/P\n8de/C0q5KYmaoTqNJITKv+YnRzr+hdWCxY9pX87yfV2OIutOJXKLUcMYOs24\nrwHGamyGvHYrFuDvWlO5D+swr+cKLg0kO/tNvcE/L+0Llr+DC087iNtKqbis\nD3WlIhplF2y4Yz3dErz7fbbYutqxyI37fUFpoaAEjOqaSkL2ZrEuvy/98xKh\nePAN\r\n=hSPU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCX9whnWKBt2XXXvAORTa+C3hEi8HVTomMjKqpVbtGobAIhALWRJKmGM8aggXFa07eV5VhJKhwRt+Fa7cCgxFCiakRi"}]},"maintainers":[{"email":"miklos.bertalan@risingstack.com","name":"solkimicreb"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-easy-state_6.1.3_1558637709621_0.5039094643224871"},"_hasShrinkwrap":false,"deprecated":"This package is moved to @risingstack/react-easy-state."}},"readme":"# React Easy State\n\nSimple React state management. Made with :heart: and ES6 Proxies.\n\n[![Build](https://img.shields.io/circleci/project/github/solkimicreb/react-easy-state/master.svg)](https://circleci.com/gh/solkimicreb/react-easy-state/tree/master) [![dependencies Status](https://david-dm.org/solkimicreb/react-easy-state/status.svg)](https://david-dm.org/solkimicreb/react-easy-state) [![Coverage Status](https://coveralls.io/repos/github/solkimicreb/react-easy-state/badge.svg?branch=master&service=github)](https://coveralls.io/github/solkimicreb/react-easy-state?branch=master) [![Package size](https://img.shields.io/bundlephobia/minzip/react-easy-state.svg)](https://bundlephobia.com/result?p=react-easy-state) [![Version](https://img.shields.io/npm/v/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![License](https://img.shields.io/npm/l/react-easy-state.svg)](https://www.npmjs.com/package/react-easy-state) [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Simple%20React%20state%20management.%20Made%20with%20%E2%9D%A4%EF%B8%8F%20and%20ES6%20Proxies.&url=https://github.com/solkimicreb/react-easy-state&hashtags=reactjs,webdev,javascript)\n\n<a href=\"#platform-support\"><img src=\"images/browser_support.png\" alt=\"Browser support\" width=\"450px\" /></a>\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](#introduction)\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Creating global stores](#creating-global-stores)\n  - [Creating reactive views](#creating-reactive-views)\n  - [Creating local stores](#creating-local-stores)\n- [Examples with live demos](#examples-with-live-demos)\n- [Articles](#articles)\n- [Performance](#performance)\n- [Platform support](#platform-support)\n- [Alternative builds](#alternative-builds)\n- [Contributing](#contributing)\n\n<!-- tocstop -->\n\n</details>\n\n<p></p>\n\n**NEWS:** v6.1.2 fixed a nasty memory leak. Please upgrade Easy State to v6.1.2 if you use a v6.x version already. Thanks!\n\n## Introduction\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 'react-easy-state'\n\nconst counter = store({ num: 0 })\nconst increment = () => counter.num++\n\nexport default view(() => <button onClick={increment}>{counter.num}</button>)\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/solkimicreb/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\n\n`npm install 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 react-easy-state\nnpm start\n```\n\n_You need npm 5.2+ to use npx._\n\n</details>\n\n## Usage\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 '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 '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 '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 '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 'react-easy-state'\nimport userStore from './userStore'\n\nconst recipesStore = store({\n  recipes: [],\n  async fetchRecipes() {\n    recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`)\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 '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(() => <div onClick={counter.increment}>{counter.num}</div>)\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 '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 value={user.name} onChange={ev => (user.name = ev.target.value)} />\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 '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 '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, batch } from '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 '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 '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>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 '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(() => <Table data={cloneDeep(dataStore.items)} />)\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 '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 any React hook - including <code>useState</code> - in function components, Easy State won't interfere with them.</summary>\n<p></p>\n\n```jsx\nimport React from 'react'\nimport { view, store } from '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 value={user.age} onChange={ev => (user.age = ev.target.value)} />\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 'react-easy-state'\n\nclass Counter extends Component {\n  counter = store({ num: 0 })\n  increment = () => counter.num++\n\n  render() {\n    return <button onClick={this.increment}>{this.counter.num}</button>\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 '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 '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 '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---\n\n## Examples with live demos\n\n#### Beginner\n\n- [Clock Widget](https://solkimicreb.github.io/react-easy-state/examples/clock/build) ([source](/examples/clock/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/clock)) ([react-native source](/examples/native-clock/)) ([react-native sandbox](https://snack.expo.io/@git/github.com/solkimicreb/react-easy-state:examples/native-clock)): a reusable clock widget with a tiny local state store.\n- [Stopwatch](https://solkimicreb.github.io/react-easy-state/examples/stop-watch/build) ([source](/examples/stop-watch/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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- [TodoMVC](https://solkimicreb.github.io/react-easy-state/examples/todo-mvc/build) ([source](/examples/todo-mvc/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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://solkimicreb.github.io/react-easy-state/examples/contacts/build) ([source](/examples/contacts/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/react-easy-state/tree/master/examples/contacts)): a data grid implementation with a mix of global and local state.\n- [Beer Finder](https://solkimicreb.github.io/react-easy-state/examples/beer-finder/build) ([source](/examples/beer-finder/)) ([codesandbox](https://codesandbox.io/s/github/solkimicreb/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\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\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\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\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- `react-easy-state/dist/es.es6.js` exposes an ES6 build with ES6 modules.\n- `react-easy-state/dist/es.es5.js` exposes an ES5 build with ES6 modules.\n- `react-easy-state/dist/cjs.es6.js` exposes an ES6 build with commonJS modules.\n- `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 `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## Contributing\n\nContributions are always welcome. Just send a PR against the master branch or open a new issue. Please make sure that the tests and the linter pass and the coverage remains decent. Thanks!\n","readmeFilename":"README.md","description":"React state management with a minimal API. Made with ES6 Proxies.","homepage":"https://github.com/solkimicreb/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+ssh://git@github.com/solkimicreb/react-easy-state.git"},"author":{"name":"Miklos Bertalan","email":"miklos.bertalan@risingstack.com"},"bugs":{"url":"https://github.com/solkimicreb/react-easy-state/issues"},"license":"MIT"}