{"_id":"micro-observables","_rev":"61-62621a07dd1d9f13fc18422295921ff9","name":"micro-observables","dist-tags":{"latest":"1.7.2","next":"2.0.0-alpha8"},"versions":{"1.0.0":{"name":"micro-observables","version":"1.0.0","description":"","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"tsc"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.9","prettier":"^1.18.2","react":"^16.10.2","typescript":"^3.6.4"},"dependencies":{"micro-signals":"^2.1.0"},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"5ba8853c6cfcfea4acbf34948de0470e1e7dda1a","_id":"micro-observables@1.0.0","_nodeVersion":"11.10.0","_npmVersion":"6.7.0","dist":{"integrity":"sha512-R80gh56nXCjuqcVnPFxC6HWaKbVo6Iml5ebosPj+uOuisZRQyFlAGVK3G2uBpcy84ntvnfR1Mt6QWD6AHYBabQ==","shasum":"c64b6e9cf7decdb3e438ad3c10497ad2bbf9341e","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.0.0.tgz","fileCount":14,"unpackedSize":9094,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdrdhECRA9TVsSAnZWagAACl8P+wddLDghdPwHXQRKfWYF\nFvNCeTYa8yvZxpQtcfTxBZDiQScLrlb72WX1PmQQJ1LCfMJVfAMF00FQkXhN\niInpsFceL3aOZXRIk3BhHXOG6D/4ivMIWf4QAuwZwmcdSynNnTI6NV0oVhr5\nlbJ/GC0jzgyUwlkxN44pDpm7lDmduhmevs8GrQv/cQtlrdKNTWmxhZtoT+or\nAWy2t3HB8BORcJaLFO4G8Wwbxi28UePjVxGTw+0yfW2XNQIJmZ7KmsDjXejj\nkW48yfp6BeUgu3PFf3JhCwjPhdiTFHQxO7dNj7zfhGw4UyDSTIv1dbyn2NKW\nPLe+gReezGJXp5aAtfohHLeUznHwDNofCwjU9SR05k61xmOxRpWMkO+POD2b\n9YGG68vTEEUphsRzwE3vgdT2Aa3/8FD8ySSo+EfyqoGzwc4YHdp943+qUCF+\n6G8XTItqU8nhFfTdJJqFg7rbwqW0sYHEIaeyTrLTBAO6bheClHP04ZkDRko4\nBh3kG+E9wjK3/UGU0xydxYOpK9Iepx/sZf8HvhpT9OvTA5YyeZI6HpRNxk0j\nZ2YMOFGvVqIIQgxa/mj+HKcHyPmBxIUTXQfCREpy8oZEtdCskHMciThRJl/2\nrtVlaFY7clXST+o1EiGE5LFvZ897aETseVYe0jr9pnDtRJgE1FI6OxPIJ0mU\nqknW\r\n=cRmu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCNkbHXqifz7quM/x+GnGIpUkB/B9wgAGvJUSdUrtemFwIgbb9sjZWcRE80AVepx1m+8c137FhpYknxW3fac8fiOQk="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.0.0_1571674179645_0.05435126405336854"},"_hasShrinkwrap":false},"1.0.1":{"name":"micro-observables","version":"1.0.1","description":"","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"tsc"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.9","prettier":"^1.18.2","react":"^16.10.2","typescript":"^3.6.4"},"dependencies":{"micro-signals":"^2.1.0"},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"42062a17a66dfce4a96383f68dc10b4bfdd48b79","_id":"micro-observables@1.0.1","_nodeVersion":"11.10.0","_npmVersion":"6.7.0","dist":{"integrity":"sha512-Xa0A23tXnbdVk/2h+rtwBwuelCNGaKl7iGxXiIv+YZQpHEETbsQpFpaacaX9uWtL0opqtF77Ah1EyecnJBOEuA==","shasum":"f22f46d5a82ec0c2c9dba6b4a48bb84f8e7dd8bc","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.0.1.tgz","fileCount":9,"unpackedSize":6464,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdrdveCRA9TVsSAnZWagAAyd0P/2Lq5BaZ+ePO5lx93iSB\nsaZb19kzf7NZgg5DPkk8dn4aCgiqlpdNjwG7N9Xd2Pl6RtphWkzYdg+EJ6cs\n/HTEfV5fW6ZDpR4redIvqn/ir7CKJWON7RoK75m1XLwn55WYfMmL6RUZIdY8\n8HkH2hxzlYQBO5PxbOcQjTx7N1pCX7v8Y9UwyIYJpaFwaAcN1Xv8gtB5wmUf\nGj1zfp72GAc4VVaQwbo64xRsNRPM58qcST3nXGSkvk6E+NP+nTfj4B/7rdjc\n7DF6UXHtptcq755lJGGGI8LS2j6IDLpJbWE3LbTMXHwV+QMJlcbmEks2ZxHZ\nQemdB1NkCEjzcZB90oWvGjIV1sKHNHOz3qycqNeuat3YsbREGzSGMqXAknrf\nrSkJNswLvqHOrO/HjKR5gQU3/2FH6eggInKNVaKDm2UhszrODmX4NH5VlDkD\nMdLb6EaB7q9iNopPGA8b1aY00+eW34bXBwtD13zxtIDlUJJ5nX3sGpn9STOR\nlHNdgf4QSG/pc72+VduWeVTGBl++h4cdut5q/RVlnQXMDq2YZXHmoelyRioT\nm047aDNtPGYyrMKmnJGnhCUhOM1f5Tv5UExYVYP3GtAGxZslvn0uxD2D2LG6\nfQkzzQQ5N2tz268QyIYEeBNumgVXv8xbH9XBL5ojP4T0ekZyfsVwrNBTmPMU\n3Plo\r\n=X8z2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCXQ/V3/rT9WcCyTyC0FIJgm64be1Bj80kUIwc8L34aOwIgMTnlNQFFYT8u2uwV+QyYs0GsR1fDoA3fmzXIBPULuOE="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.0.1_1571675101583_0.5766902520808361"},"_hasShrinkwrap":false},"1.0.2":{"name":"micro-observables","version":"1.0.2","description":"","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"tsc"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.9","prettier":"^1.18.2","react":"^16.10.2","typescript":"^3.6.4"},"dependencies":{"micro-signals":"^2.1.0"},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"ac2feae38496dfc2bfdfcad8467c3bb289d13d5d","_id":"micro-observables@1.0.2","_nodeVersion":"12.13.0","_npmVersion":"6.12.0","dist":{"integrity":"sha512-IhHk2K77oWwf8PU6Ds0PK/LvVoDQiyqKOWL7cvWyHdd+ziQSJMBC3bPc5ih5yX6tJcL8FyqQqWXDoXcqbdvlhg==","shasum":"246b72a2ea408beebbb40f1b375061c79aa7c3a3","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.0.2.tgz","fileCount":9,"unpackedSize":6724,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd34uFCRA9TVsSAnZWagAAN5MP/j8He319C8tvREJP25m5\n/zTIdVLRwqLeIai7qbTZKlp6ATZzPIi/rrBT9lPy/XwhNIYHHAuYTVEJU3cF\nXgayTpGJQ/6d//8HdTsQLAAgEU23IXoTpCLTJ1uUWj4Piu6XDEpXpvYKI6i5\nUv4mkc16/HFBAPz/dmir/taWEjTo9XJFulm0BESJmk+uVblySjG6ffxtqsIM\ny2zaY8H/aUreKyKcXq21TVRFQ4FJj5CyU/5tvXSR17dJur121It1g+abp1Iv\nyU2W0BUEECm+YLbtq6R28ilQcCkplasVGaJLKK3n+a6JZnVISnsguIVqyfFE\ndAkScsLGZDlJST0jwHmNZxDuzi1pTW/n4wZ0VUeK233P5jlQ2XLIkxUhxO7D\nfsBhhvLIJTNPtkvR8HJPm7h3z8gb6yWQeqjPhOdWbIFUMQoQvO4EqS0WN9Y0\nRnNnt/AC5i0lJzETVeS4hX4WaYecQAdhr3mup8VlZbff1avVu6GMLr//166E\nnwQNu97xBnvcdHUJhGwqCmBJUjjQf+PTEooYGyKBbTF8HkLLydo4EG1LDZ7u\nzfcJWLTKsq4LzCO04UMmUBnV5+WYGqdQMSMpeY3ERAazTwAMcg4vCvpe+zIZ\n0sZLnC0cxdkyEpWW5yBMPIx07STe9tG3T1vyAF+mJru1gTvb1gHOhZ20S+TM\nniss\r\n=8Y5R\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICtghYIOgmZVHMxJ8/PBl94t2UHVPion3reulOcFAGjmAiEAvVu57OIT+ZdA+86wW/taGK4/jWTM1gh8/23J/rXfg0o="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.0.2_1574931333442_0.8898804300167158"},"_hasShrinkwrap":false},"1.0.3":{"name":"micro-observables","version":"1.0.3","description":"","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"tsc"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.9","prettier":"^1.18.2","react":"^16.10.2","typescript":"^3.6.4"},"dependencies":{"micro-signals":"^2.1.0"},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"b304175d45ad704e61b14c05a60b79a04e61a224","_id":"micro-observables@1.0.3","_nodeVersion":"12.13.0","_npmVersion":"6.12.0","dist":{"integrity":"sha512-CpX6/OrnYMHz48w1MEUQommqtBwFpcxqi7OychZ3w9gMHn5UkBxWIBHPD/Vn9bdKfH6hMOibVwSJTw1tL/Fxmw==","shasum":"dc9f1f6a471377ced532e687fa969f0680ee8643","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.0.3.tgz","fileCount":9,"unpackedSize":7049,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd359YCRA9TVsSAnZWagAALyYP/0Kxbzii8acHnCf4qd/e\n4ghyW5I70OgHTT3WAZqEhL575WGHR4tyglasqJGBCTCOVj5PhTachWwgm8cz\nOiL4S5kz4GflHzPtoNhrxtCtPQYA8i5miNsgcSwkta0dHfhsS4NuGJkKxsz5\nYU9z/9nhmj8hgSb0LvUCd/xkiTmUwrjfQB4cKPIKJzQLIVhWi8YGJ/LGRYUC\n2CO6BXT0lOHiBmoFcK1IiF08NPjGLOOEpHa2k0AnLv8DOy8AMECdxE8Qy4M7\nEIcjzifsGa02zIlHqqWI4xNlTYF9O3SLtZeQWliu3lmVHZP54q8oaN5+lo+A\nQIXi38W+sQaA08O0Fw0mg8ps/a7svAk3JR5YWuK0/+8sjnqPhrBpNQIrJ/JA\nvOcGg4R1bwau8oIOurhnmfnyYMxoq0lt1jYG1CoL/NT7fBsZh6tDyPXX40lW\nfYoAjvENBnd/q+rnNejbhu2RmqVb+DwLrnmZzAb38IFBppoBnB/wbLdAZXMm\nkTV/YNLO/4LPzBIm/11+l7mwJoxSCFopyU5Y9Slzsks3vb6nfJ9VSgYou8v3\nNUQpbQcu4wuMQk87mzvdyJEtjimnFA34LDlLoeuH8A/VymaMoR2a0HRJgLqv\nG/BptAW15xdy4FcQGKTJww2/jNvdQlm/L5C54Znr7qR9/H2hRyepf625V4fV\nRiUu\r\n=g7ff\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFC/oDGjQ1MWPNQsEfx66x+yUFFgDpVGdAUwV4kHKK/WAiA8lpzcA6rtUgbT6ja4hvia7DN89UeZcj9iMvKCuthc/g=="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.0.3_1574936408202_0.4436562620076774"},"_hasShrinkwrap":false},"1.1.0":{"name":"micro-observables","version":"1.1.0","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"tsc","test":"jest"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"1a86df41113944fcb02b5335ead6e1ec0e7f3c45","_id":"micro-observables@1.1.0","_nodeVersion":"12.13.0","_npmVersion":"6.12.0","dist":{"integrity":"sha512-NDLtAojlLNzPj7oxHp+YbqsQimWyPdio8qiYCFk0Sg6QII/qmZtgO8nGGHPBzq0Gupv4a3531tbk+95Wa44tAw==","shasum":"3b1af7e5f1475e660d23d33c1199cf8c800418b2","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.1.0.tgz","fileCount":13,"unpackedSize":25848,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd+mIHCRA9TVsSAnZWagAAjwIP/35Ca43vwNyVhyt8U1BJ\noGtB7NYz8kwkG5I09oS1DV6UcchVDtfYm1/gb9BuRaM5y5P54lK+Yu//Eslh\nLxR1VSxEgOrK1jf42MbVKxIJ+bY1NWYJHekzvTwcf8QYwRNN9qt4Vjn0SV0R\nyw3tSv8nzu5Pj8kC7GFnJjRyhs+ZMlDmEPgISfMZK/DZzymNG/r3nmefTh+N\nnYEOF6toA3lzpos/PkM/J0DnHJZeMlNidKcqMc/AH/pHtUQ3fQEr0y4/L6js\nT2mqfW73x2HUgTng8/tUSQUG+71Mc2XSoRuoRBxo3cAfdBALjHv7Zt4Hj+Ah\nn1qTYc0O2rfe3LkijRZ+1hDDi90G9v3enppZQw/31HnNWrNb9dTKi4CHaE7v\nJxFxZupSiQpSpfhjEWBF5ZWJkR8T/4Qzh/takmL1en0m2NNV6qQZiuAg1GWR\nQIsJ8mmbHBa1UcCoF1NG4RX3vuPLWvMTpWHcnpfDUaFYKgwCEGjV/2Z4otDN\n51TrE5fZ0+jq/2zcrMibCmWWqvyuP9ADV7Y40eadiA2krbE5OdxAabvPNfPc\nnkZLpgcPUHkI9k6l7YVIo2v3LWZ/0Np3mJZpSRfNApwk0VcqqEADSTrfsiZM\nNIpPjswXOWY2n8XA6EjTfluOCsNuf5e2LXLox038vspeavOdPberm/FZBKYn\no2qz\r\n=daQe\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC8N6YDglufNlcvNL5dmEsdXtlNOlVcau3MItHSR3K+UgIgOVtIHlq6BiM4Ffruno+NDXZYaXFcrc+fnGtFLpGcBXg="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.1.0_1576690183202_0.955869100908376"},"_hasShrinkwrap":false},"1.2.0":{"name":"micro-observables","version":"1.2.0","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"tsc","test":"jest"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"a4061b0a533618be5df339b3a55751c7ba0bf4a6","_id":"micro-observables@1.2.0","_nodeVersion":"12.13.0","_npmVersion":"6.12.0","dist":{"integrity":"sha512-YU4KjgQg/iybS0FpkYaOkoaBCJstJ3mzne8QWpcceypM+u6IVI8mz+Uz0AxvAy2GbgwUkaNDYYIg31KuEXRzqQ==","shasum":"84fccb7bbb4e60dee488695f0e26215b304eac67","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.2.0.tgz","fileCount":11,"unpackedSize":25839,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJd+0A0CRA9TVsSAnZWagAAcywP/iBvnWOTkobt3cHerkg3\nbEOeZ3dkIWb+CbGSBgS9li6RJ/D44xOAu5HfVBQOrBJKzQK4WSsc93RfChZi\nTuFMCBZC/cLAcEeRWFS9Z8U7X7lGnLMR1GlXVp7fTtHDS9LG3/qyvWsj6i1u\nsvHIEGDt/1y2ISjgnEkBV2j1+lUiFvIogJQltmiTD5GHkqHR5l7bl+vctczt\n9FnpKJSMBynV3D0lcN5nnSPeq8XWWAeltS8ScOnLSOnlQdKr5P3Imv/VC3a3\nAR4mBt6UC3m50ZBJMf/zEUU6iGBnm8yNSnagbgUVaPQru6WUOfdmFU2UBmXm\n61RuuoumgPeewRCTlId0UVeKddkKb188iJ9VYwEbgsu9pZVtRcqMsBv30tNk\nxR9ocL911culrfITac2cFlb0vP6npQ8vdjaFJzKNJskUKqptSjO3WCMR5g/A\nhk4YV/zkwA1Tw5r4Qbr9zwLwDd0a9EkLvQVVo8izw9ZOmLbDVPq4gdJ1FVCV\n5D/aZovw+4ZmSXgiGUvWD/wBIcktR1YHV5IsGXVF2UYluT7wFzrOV/T1adIL\ne5geY1zcWaACjGUBa67jl2e6pRh5Qjxxmp+HRsInkZJ1hrlDj+rdUi+0lcMO\nTysvatD3/AJ41tbb+zThYEGvswL1ftNytipCAUmX7dChdpwVCEN9nH+q6o9w\njVkS\r\n=W/1c\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGyYGSy/lrRxgRpOZTG1EZDtTc+SXIW5j4vLJbxanpSBAiEAijgkv79N1MyOaU3IgWVZCMdilDFKC7Qzkx9EukXM2Uc="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.2.0_1576747060423_0.7431781541998388"},"_hasShrinkwrap":false},"1.2.1":{"name":"micro-observables","version":"1.2.1","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"7daa581ee3a1b618e89686076ba4c284c777bc3f","_id":"micro-observables@1.2.1","_nodeVersion":"13.0.1","_npmVersion":"6.12.0","dist":{"integrity":"sha512-D5fjMlnqATierkM3ki2Bp+lMNtUuT45Ugn7XvNQzaxU/cMhri9BbL9Frvacd9EoYLKd6dhXRCH3H3wufNnxuNA==","shasum":"7ca2c43dcafd4cc44e8c3893341848fc2fddf501","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.2.1.tgz","fileCount":9,"unpackedSize":21885,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeCwKxCRA9TVsSAnZWagAAencP/Avx1z/1+V1HX48Mtc7B\nycOybWoRAZYgvC7RgDMiRiN7ICq052isq9Uy5fDGABiU7L3K+Z5mJ/MLyI3q\n8jaPTqu2lUy1E++OOMznCb0jyHfdYMYmNkHhBdgLcwpqpJNMZQcMi9i5Dnnb\n0dobJUlzUi5ELnfIris6YvFmh7GS6ZonHB8YR8KSb/+ETgzmWJai2RR5znuh\nP/k9lvtCFhveaS6yM8SbY6cHh7ApW1W9pGzm3N2CX04NLAglJYUz5QoP1ztZ\nJ3m7YMHYM4IEBYKmzGop0D1KW8DqBDaVKdX+M9WapPrwUWr+zOTLn+68FWC5\nOv1XAczIzFqodwz0312UWqj83zPXRxm4sl6fX0RDSpfXwbJPal9iT3/bUgv9\nWCQGm4JI9lPs1vVdoEnuEEMEePu0tVPs+aIqYYJl42+ht+NGSLl3IQjY87oa\nmz1nRjIST9teckPcMinGiX1EPXMaU013eQezI7ZqUrsZwjXHeJiJPCXqsInc\nKPpUFF3wg27nDtpdeuTryyhZDGivxenjNnZhgFclhvrMjWFqx/L3i8FQoQYi\nqonNP15HJqE2utHGtHWcb9RFXX5TMOJFF8B9vQL7Giw8BadB34Zkqybirb5C\nP7jEveT2gPQ5Q4QNGQXrovkWE/bjvWbDmAlZWVSnYQZ1kgda3L7AbAmOITEl\nr2RW\r\n=rDXt\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC+niD9nCXDPW4NfSgq+uQkr4GQhw3qXZwwA/fo5G1pmAIhAIfXRRPEzRQL1uRt8s+EmP/XbRg+nCXrk6EWxO0e9i/D"}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.2.1_1577779889035_0.8301179085906896"},"_hasShrinkwrap":false},"1.2.2":{"name":"micro-observables","version":"1.2.2","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"223fd9740c0e4b51af5106162c6d6f12c4b41370","_id":"micro-observables@1.2.2","_nodeVersion":"13.6.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-wsxHkx74KQYcfOum1ODktPcw4ck6FnynX2OwIaN9qQZvRsahNoPJxJSQGVpr47g4LNx9hNOyD4BVUmuumI0UEg==","shasum":"f3e9b35bbfc04fd3c8b1b496b7d58a7b969a1489","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.2.2.tgz","fileCount":9,"unpackedSize":22276,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeGE5xCRA9TVsSAnZWagAA+OUP/3NVas8EAlosSh2Gyrgr\nvP91DDDZZIqcpwZTdLR7ph5haUSa3I7dp9pOKRACcp8qwtyjMgjXcfblM/95\n9gvli3Ld3Xki1byUlvy2QZO8PLSIFhFKaHrRBVwas6sZfpGWNeg+gJSeRIsw\nF+jTGcp/kWS2JJtWA+dmZUSIeLnvRLQAb4i9yr7yLNCOBo9fzk+VugQGbx9m\nH3i36XAdulq2Lf3Gfoo8IjfVZPEInyr+FHx0187cIwAHY3VHLGWT6rjk2412\nx2nxqBjQaFR3uEIaadrJ7eWpiTIIqugJCaJWihGR7+ORTgpW51WMFcPiX1Mi\nAqgQdWLptILH9BY2jKGpNFj47HxR/+qCu8vFviLsXq5FTkARoiKqgUOSEB3w\nAvmkuxDyyim6U2JsYXtTKZWsXYyF5pH8R2bFwZbnnb4bjyyfUpp0o/fzVAMO\nxUkQZC1YbsFUxx6yl/8Srp8oZrL7USyEyz7yoD6D7cJH3DjiDhUqNhiUlMQH\nsQexhujUxYwPa8HLzK4cnxutZSI3oIdIPrNM67rQCYYnkH1mCl79WrjGyImA\nxPdMKT4TRfjx8mq5+vMIiOHgQ7QGnZN8remOxfqvlRO8nIwYAt4EPp43DHSz\niV4P6iDzvq/DPR+YVp7RdfHKdvD0dO6HBlCbYd6e11xHMpCehg/YCceaLdr1\n/R8h\r\n=qqxx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDWfPEbohCc3wSqKd4V3HJ9SjXrmbC0gl0WwYCULZxrQgIhAObxdxuUTF26Zc8X6n53iRnCLSs73aliHn/zjvC/vlqC"}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.2.2_1578651249410_0.34182487045192556"},"_hasShrinkwrap":false},"1.2.3":{"name":"micro-observables","version":"1.2.3","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"6aa640d08efd0b9906cb463e5c1b1ff6d9c30e97","_id":"micro-observables@1.2.3","_nodeVersion":"13.6.0","_npmVersion":"6.13.4","dist":{"integrity":"sha512-yujJK702sqkf1WSLChKLD+Ru4Kp0FZrcwNMzIDl6IKKzHxX/PKkHO3noBAkUBgI/Xda5gZxktb07X7Pp4Lnhog==","shasum":"b3ea1eb52cc58e4d2a6ee0b31e23b7151079ddc5","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.2.3.tgz","fileCount":9,"unpackedSize":22314,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeJudgCRA9TVsSAnZWagAAcT8P/R6l9ibWbk3jlBVSi5Tu\npWKA78CWc3RKHg0B/sHPcN0bW0NXRltXFl3QbWSc8vfGlus0ONFmi5X0Szpg\ntRtNBgeWKPFrBmjrgHFCycq+VZEHMd+SgtyYcdQD6Uw7BnWfIBelQdh/oCu/\nxy01aeWchtfmB2LtbQuhVkp4e5nPnat1n1zILYrji1NZDof0CXp8vbf18mdC\nCRKrEcRWqtx5o7dm8bzWR7VPYLOIBXL7z5hfnGTHXi7Z6aXpBIeuyaKTnHcf\nCRZrcrTLVFUBL/++oBzQqKI2XxVn8PklUU+OxMz6pURn3036iI0LZvhsiWYx\nPCy1cWvqqPC6PF1cUmdmUnsdGbxikmiiN0HcLIXUJFd8z4w9/dzUfNm2Nciu\nzFwSq8zvX9OAv4Ht8a4wpZd9YvSNJ3+7QaO8I7k+XIF3LTbyXersVd+03WLA\n/+iu48UVzRPJTHTysGRKrkQfLUp7gKX2VNTenS4TDtRbCz9fFngxCA+QSbly\nPoCJGQ8P7LRtFa3nqHt06vTqrYNjjQBg5Se49p159dHHo5X/caZrcv7/cXft\nkodqDzvkGvzj8wPl/LursHHfG5cmrFQyWfQt7OkSOXbvRlELivbREQdgCEpP\nBHJDjxdVJ5oRoBIxxNi4cwsAxcS1Oo2v9432MIi+K1+iHBJn4HBFy1M4h8f7\nZuQ3\r\n=Cb1k\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDlL1a8g7/rsY2JtYgGhO35CnvCojPBcQhs2lPClWMM0QIgVzNCwDz52j6kbQxf7hsarrTLQS41xpISCHq2YKwC22c="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.2.3_1579607903694_0.0009073799376826397"},"_hasShrinkwrap":false},"1.2.4":{"name":"micro-observables","version":"1.2.4","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"4584af9766786ba312a660c86936279ee7431b6c","_id":"micro-observables@1.2.4","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-+bAxf4+Fc5MZA5pfTh10h9zARzEWOfc+Vy3w9F9Ie1vrK3f2UTo6jxd9iYGYcdnapkisT8RUAY8dgpQaUqxfhQ==","shasum":"69d8fdc24a0f1dbd25f306d9fc0739d1c1895c28","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.2.4.tgz","fileCount":9,"unpackedSize":22901,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeLbnTCRA9TVsSAnZWagAApUgQAIXnFGxRTrq4S/pPDjys\npy0+l0ku5P7QVHh0zUrsUnRSA9lF9ab6xc0/q8T5Xfov1fUQnmIjz0xQBRUY\nJyJdYdNTbuIVSX/U+CONPzd5fWZEg47skMdJseUTK1CconDJ1ktC174Mxj25\nkEuD1kwqJjW0tlWBSlW+MWwFZxi3kzG9cRhyriohuWhY403k+3f1QmWBSFff\nsfjSz8X8LHYp5uvZmSwCSfF2mImjs2ied9KduLi/e5qXLa4YNS+J5xLP1/Au\ndv/LyRTY8QopeZZ/YKrPGTyBYitg/GVdgao2luZtY0A871n6e7tCW1RxdmQb\nmqKhicfhqWV4qPoHY/BvOVNnutduqO2dw9nUkxypt2mJfK34xxgbemc7xP+f\n3oxQDqvbpIO8rZyixoFZeHOC3f8et1U+fea0IraGCnmpIUQXQ7VdEA7uhaxO\nKJPMVTMNjVj5zwzi0VGtkstjYnKdxV4/+MVt80shO4T5Ml9Hxcx4IhxwN/xO\ngVnAvB6XsDI0GSYyhKKXd2+lEIH9GhbZSyRDfGm256UAehEVdt5GoOQiU4fc\nky0X9xM8MZphNv1abRgoyssuBj5i0vXUXtpC6zm+PGdPRljUAmKxR6YWIwMn\nc2zcQg1iHMfsBKcxWTAg/DqLzkI6XxklXzL0G0B/HQplrcj7+wH0fBsb/Cr7\nmIxC\r\n=7xdH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFJRp+LV8wy5KYrjcQmOL7o1qdoelcqKpFNJhfpZ3uTfAiA8v/r0Y/8Vy7aef4nmht0zODNUOgX/zMzPr7eWmb6C+g=="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.2.4_1580054994979_0.9339264480885088"},"_hasShrinkwrap":false},"1.2.5":{"name":"micro-observables","version":"1.2.5","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"d0561d45d80831a56e1ec10b067a05e7d1c0c8a9","_id":"micro-observables@1.2.5","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-A/IDdtsM3Ra8TJsXjmwhGSU2Z2hfK0JI/A/tXGY7RgHAzrreCJsuUINPKkT6Zv6cMWmMyAlgAiwySc8+F+0iIw==","shasum":"f8abcd39407e72c75d27f9e5b0c60070466f7e00","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.2.5.tgz","fileCount":9,"unpackedSize":22857,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeV953CRA9TVsSAnZWagAAqy0P/A+hAQtxNtD40xgvXKRJ\n8wMUo1ZzG0aqFQrxtMMVbbtugzqRckIFQMK9gGsj1Zv41MX7hjCKPVZDI7FG\nWtaNfnzlz1tHP5OtM0UgqFX5/Cxk74bmRykrem2E3mMqhmux+pALIFVHhhlo\nypweZAgl3fv87O5TH3GigcyW8P1ewLyjVPMtiu85FjwfM0oQYJV16ErbjdIi\nW/CQG4aggOj9UsJIikFpEwplrnZy5YFVvjTio9Sx4PcJ7i+nIUezNy3pnMH4\n7ynFWgdLraGUk6KDW+Ewx+bd1B1dlZS9JxBzhx0y+THIkjbrkbErbp61A87f\nkA+/TuU/M+JkC49n4l9t1RJZwDqBhJya4ZLjOLzR6kZm6whlQvHx8RpkLXxg\nSVNvm5CDY8Wdu4VXmUPIsQPK5K9xEEMFgg7p+ECGFP95LGIVgMcEtEDpaU3D\np6KQQYLaKGZLsD11kEkC1RZIHj/1ahXZL9bo7cDI2bhP5+AfG0HtYsou6q/W\nor7710DDS7UOTU9vMokBbhtjCY1wa7oSiNCJhEaOfdAhjS8RA/910OELtGJt\nXC94EkIMhN2EL20jKjt7mrC+mB+zdz4AsVVK5I5DNyo1etCQm/N0nQbZg3Bd\nBWuSG7pqS0I0yF6/8Qi9I18pEqwExm3JdZeJPzAhJQr6A4EW9dp6i3bq/nym\nRBmP\r\n=0WRv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDBr2N7nEMeVwqek3z08iiTBI5ZodfMUDfaySOoEwnbdwIgZIJbVCdaCLKY6ZjBMDNupES21SkR/QHZ0BpEH8vUCWM="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.2.5_1582816886616_0.21811565781194275"},"_hasShrinkwrap":false},"1.2.7":{"name":"micro-observables","version":"1.2.7","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"154be2c4eca18b9a60d027eda5c2bffff7cb38b7","_id":"micro-observables@1.2.7","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-80KlX+F6Z+mxyQLZ06lZvpBW4N0hjzKlD36Otd4QdYz6XGLG8bvxOti0LSWQY6HlwfMwKdbLFy5Gu4QqY5Y9Ow==","shasum":"1a410ad00dfe79d54c09e3da3fb95a77570f4e22","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.2.7.tgz","fileCount":9,"unpackedSize":22887,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeV+kvCRA9TVsSAnZWagAAx3UP/2eo4Ft+5ply1R0Lgjgq\nqMSbiL4eBBBZlYXISOlUX0Lf3V8xQvalxYQye/IDORNw1yrQCJR/5oegkHXP\nTm7N6NoclNkiEmNDXjCRYz+7aQCLl35AKxi6j1WDxLHTHzoEKQjEQHO0YMgO\n8Gt3/1N2basS92myBiw0xVEbFJOUejbD5V0CUZxhSqUw7PKRnzDyNO1WuqoX\nF2EbraPgowQyNntjBIrVHA/0PD4tp8YhUDqVf7/NTW+0jLV+/eBro7Pehdn0\nIhxJkBu+g4Nri5n9/Wjv5LZzZytfHuqFnARMesgUH+BfTqZSpao+05gBrV7u\nl/hF7RITWfs8d6hj37W4Bkj47v6n2yaMkorau2G6fOkuTK3/8o/kWq7+PGAE\nVw33WyU9BFnVPRs0v9oZMBT+Eu26r+Ue2I+vdMDepsLuNu3do6BntOrZ/Yhn\n3Ty0zHNehG7CImOitW+T/HqXN02F3oTAYXVE59pOVrBz0msV4tsoHzHI026C\ndawew9m2J2bxvjSVc7KhK0XET78H+ZSlGPDt9vm4247SvIhNv8yWs3TbJvyE\nwkLaOJs5jyZwgx+ovRFZg1Jm3nb5fCOPTIP/G+JdGdkTQnuTvLhEAwm4iaI9\nVWumt32I7cFHq1wNfzGcR6mj2XSxh3YTtqIRsJgFMKmSRWQnu/lw4ffgn2k4\nly0I\r\n=tSUZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC96fXzn6fTrz8fviHjt9MPPuBEFegsJWyvsGieV13VHAIhAIos7K+s8wPfHEAfLHAWGoPsseQshGqgBiRvJa5g40hb"}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.2.7_1582819630548_0.47480613055401677"},"_hasShrinkwrap":false},"1.2.8":{"name":"micro-observables","version":"1.2.8","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"de9a8be9fc28550039b94d2f9dab8a809fb68bd2","_id":"micro-observables@1.2.8","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-n9Xfki/sPBsjr5rKeUQ5xvt//Bb5OxQj4i2C6McR8RtMPC3DZXvtXeXuTMBieL8PGuMtlcjrqRnspa6Yc4NP2Q==","shasum":"cd6ac9ca20536817ad7479434c92b23930e41ca3","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.2.8.tgz","fileCount":9,"unpackedSize":23097,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeWMiTCRA9TVsSAnZWagAAlowP/26gtNqdSx/UglMaCuYb\naBXOYe1Fy2BGXVMMuL7egBx3Qut6Crfu0M8GeBPeYs7wCTs+UJHafwJG4e8C\n/W3DPj5qfyXIOJU6sBginnzU8g69jWUCNo80imh9CYy46z6rK/H6lZckhuSy\nGT+nb7UkhxAOma2ak7QEcx7khG4iUWkflhUZQ7ksbBg5wdLLTewW5vQjefRl\nvimaPyJIzH3MTwn7BPKyzSMoqGkkCR6FO7KQa3EkPOPD9yw+cs4AMIc1FxnG\nhfzkAZAQIrxSDCqVuv4YyjoUVMNDf7dP8gBE/sY5Kmw8htvd3PV0P+nX+ogV\nAYMKkCNRS9bL6aRaEMs0XapOwMCfMGDUnUAZ86CXBV2i0kXf+KIYmiwwSgxR\n1saeg7A8NyqRv7mqqbPRA83O0GEA0j9MDR5ptuuprIMHi+k4FvwgyWH8JLU7\nJPavdTsBUvgMMYHA7OtgeU0hVPejRP1U2SwvfPbkCgtM3FFXStrzbS6h+jpe\njitCJlEXMB2icunMjLRkruaoU5QwfTuyz+ifI/kwS9daNP6CJzs4M5FJa3AJ\n63BNDzbwja1kDl6Qs30kcO58lSZs6I8Nvy1WsbQBOH6Vuq4FHpiBHe1pioKa\n4S9g7cBBgG3aZmj+BCFFa4H1hyzRI9o4eiQYsNX91RGv8icUgZgTp/0xCURY\niHki\r\n=hW8P\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDFe1ApZIBFqBTS7HfvXDlTQSeQvBfDZS2qMOg9N+zRxAIgHL1WDPY/27VjlH8/MzNUprOLTkn7qR7aWpoI+nzOmFY="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.2.8_1582876819140_0.7719806455827087"},"_hasShrinkwrap":false},"1.3.0":{"name":"micro-observables","version":"1.3.0","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","prettier":"^1.19.1","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"f785ccaa475c129bc3705379565e2f7e91da68bd","_id":"micro-observables@1.3.0","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-OdVLDNwcDkBOyDuZu4Y8ME6cSzUIlpOE05X1TI7TAEGY5fmVVZhUZ9MTkFiJjSJW3OHEomYPa/40cAodF4Yf4A==","shasum":"ac6348b48b5d32728784e3ccae0783937b8c0f0e","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.3.0.tgz","fileCount":9,"unpackedSize":20965,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeaQpzCRA9TVsSAnZWagAAJaoP/RrUWq1C9r20KAbHNwoD\nENDpHL/chLO2ADkoWogLdT5H1n1+BOBoZkqacK9PDIcuzq3VFi2fR4aoLnur\nr82PSpWKVPbw2iBIk4aXzyoJqRLZDuipI7zkAXHCVkY+8dD5hWA25UbMPLil\n0kYexh/9TpWBcj5RKK66r0m+Yv7N3Ti9hwyhBwnRHZDXUDHaSDAMnZDW7cUy\nYWHsNR4UR4MRsWCgsVAYcgrW23aOinkjWuEdxRzNxZs4+1p/2b6V1EykYvFX\nbSec1StxGoybr8cRL3exk90VZcFTNeDxspH+JRWz6QFrZHb1/o/RyQgk42Z5\nus8xEPrY0vTjqpPPT/pPjDMSc8E1Nsg/2Vz/ZaxEYPJK/M3Je4XzJy5BgaUf\nF20jBbpEdqfvE+LzWyIqi7vM8oC3/jVkp10HMsare0uQWU0nCwpmcu233e5k\njGmh3D2/hrkyiHENjntXjDTfZ4mOmgMm+ciqHTpcnQETZP2orHWB+Xykzzy8\nhRC/D/tS993tHAsE55dbhDWNI91eJZJtuFv9qVyvfA4RnMPgy4EaAbnPzCi7\nPFbDB21CCRrLYDarM93KouozFtnRzPuXr1fET1YHuEBpeFA7lBZwmwxcAjbC\nmll/rO/b5PvLnpaWnrXI8NB94wqAu0kQA2lVeH7wDZipfkx6olDIK8FWCzg9\n8Y7F\r\n=Tlna\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCU3NlvoML7dMC3WqMQMdxWfItCqd4JqRgtPH4pMUPo1gIgFs3z/Ppe2CCJJPBQCSAGSt3gq7v0tcX6DKt73LDmsp0="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.3.0_1583942258806_0.4894833384912778"},"_hasShrinkwrap":false},"1.3.1":{"name":"micro-observables","version":"1.3.1","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","prettier":"^1.19.1","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"da683869d41e8d3d428f6721883aafd26cac4cb9","_id":"micro-observables@1.3.1","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-bdDpuel7rv2/Oo/ZGb4q40YYxA49VwqNORWmsY0W4as+ypIYoNtfqoNN42RcJaW8wbx/iCaXxRIBL/zUrnYDuw==","shasum":"ae96360a2152bf8fcfb422e46acddca2b8340ebf","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.3.1.tgz","fileCount":9,"unpackedSize":20265,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeeTsBCRA9TVsSAnZWagAA+CgQAJrC0epexYLAW3V/ffPB\nzZZCA+Dfnkq54MVWgPXPXcsDGoY2huUIY3VfkhfyeGm6zdC0IwcjsH8shJ2m\nNPZH29FTUf9zUw3aEyx5+q6tMn0PeYDC789gZej7gWFVey5watX0uIr1xh8o\n7vMN/7SpYIAfDYi+Powr8znBVdSnQvAoYgChw5kM7QPO7nQ4J+RqlPljuktG\nJmhO3jf8qHIy1BobKgvb6Uh0tw12hH0GtGZatDR99HD91PfvpMnvKavuhDn2\nAF73tPkzhsMG+GKY5Gx+C/hmcI0JDqqpQbXKuAcQBb4w0B1KwsTH3QL9s59+\n89CsazLCvHQCaTQuLSQVntopJHaJWXDvA0+AsE0lnGScQPKsx+OpX1RhefWd\nevJxSIz/usVV8weXhoQa2i2s0Knnp3QYLfwk/gTuszRHP5yyJkTJnd4snZSp\nvlUGBJY4s/iRQ20zc8hfdYurRZ5JsLsLSRQKYFi0wSO9cEKzFxK/6IJNd389\neJ4w+XxTapgqTxICtez9Phi2+YZ+fh8PTg2p758fh2/3TkwaQXCOPWWOpKdU\n5BnmGfoxDGMJPrUTiInF8dEPtVuiS9oEOC64fPP2h9dEWJQT79ljkZ+klfv8\nJaGwOoF8qCZF6yV5QaA0d1ldbbiAJh2q+s6XCyzRsDDhYaHYF7q5n1fKbZNd\njYuV\r\n=cQZp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC+mdykwoxN6SHo6i+BmGZiiLNRDkvndPyS0TjJm9+RPAiBFUz6mtY+7rtIHzFhB8lQGWPfxJSRlileTUXexnNJJYA=="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.3.1_1585003265196_0.12737651160907748"},"_hasShrinkwrap":false},"1.3.2":{"name":"micro-observables","version":"1.3.2","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","prettier":"^1.19.1","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{"memoize-one":"^5.1.1"},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"f1f45af5d2767111a2d199364ff1d48f56356467","_id":"micro-observables@1.3.2","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-30DEjFM2J3UibXVILEfP3NiveZv9JNLJWqWAlJLdd7ivvaAcnzY1A1VrMNG6nv2vR7vR8hjYZrkCe88e2UZFpg==","shasum":"8ec834b6176d156905f689db1c198cca57c13029","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.3.2.tgz","fileCount":9,"unpackedSize":20566,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJegl85CRA9TVsSAnZWagAArjkP/R5c2kBcGo2cvmJ3wiMb\nQCrqVkqBguHTQfVL6dzZqoVQoZ1R5RXxT9rLl3i8POLOWajsc70A/mghoHc5\nmUOLJVHRf4EdJ7P7NhqdBCam+y4vgmpiTt9nvW/4f/GwubcaXz1iCCiybfJW\nycfwl61dJLHPswgGWvizPlB8HgBLFNCFCSOTmd8X8bZLWw9xHvAqfaGPUZYN\nKrbDs1jF00j5hLP0HLV3OJ+93OmXnWKoN8JglgXunea/p21vlxYzWoHeXFqb\npNqBeaookzLuAzudbVKr5f4MO9ZC6oZgutMY5qlWwTOAwqqlSw0oS80k9gOj\nv54hTNVGmsYD9sf/Fzn10/uYwtDRaHUr8GKDi6lYruG/+qv6ayc4FqB0+ObR\nCMENlvRAMFHCR+cU7fIXiQERc+OhggO3zUKAyMCC+rrX/FuI6KLtDQFxQXPB\nfnZOHvv7iM4cjB21JMX61ngW9KD1rI8/CgHwiBrAMiA0A2jKOkkgaNNRopyD\n2abcBK77XJbLgWZq2x92RlCEmlvdi1yIla6IoRIU31lO5Mp2eJIpywkT4FOA\nop/3MpoY2kH219JKfo3zorwu4cmK4bLtaBREoz/p3by3vR2kDexJHHEgZ//k\nwZprr8Fx06V8hLorpycPe1iXW/XtuM/9yeKDRT/ofj0l95WI/xRY0AK7AT47\nRn2S\r\n=Chch\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC8wIM0u0wwycCxG9FgZa3JBsydMNO/iCn7iDXKESGLsgIhANi0NQgQaIk57YhuzqDRy57QIxl8SdysfCdpGkMfnMt1"}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.3.2_1585602360819_0.22967599589214016"},"_hasShrinkwrap":false},"1.3.3":{"name":"micro-observables","version":"1.3.3","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","prettier":"^1.19.1","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{"memoize-one":"^5.1.1"},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"5236be1a5f1d37b3fe80313e9a6851b3e662541e","_id":"micro-observables@1.3.3","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-hjnKKDVOTpNuXjvzSPM0uVcaWBT+KEvWJ5TDc1gkYLhk4Zbd9zBzPEmQzxWE5/lhowFGfr5LmQQXiGEz97BTlg==","shasum":"54130fd391c7d477c99472f9f6ff29976f1c4ca8","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.3.3.tgz","fileCount":9,"unpackedSize":20688,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeix75CRA9TVsSAnZWagAADsIP/R2Tb6txhwAURdiCxyJP\nqjnZs6kskGWyimKhuR0o6x8wxMKyc4v6/F4S99fRf7tDXxdrVms3QvMhE6O8\nCJPG7YG2loNgbEzcCnJ4v4uYp7UCsdiwiiB5bdrIClRkvlvrX9ks+fdHM4AR\nw1M/02N287e1+kXdOYSclLHSir5ExcHQoHpHAKnXc6J+x3IlzVZAmwsv6MIg\n/MoqZJxMpBcblX5dAR8VebuFWYMd0l7asJoexH37WKeY47wIqej2ykFzUzoT\nsdO8on9S/JRqLZpnENAAzEA2f80lj/wBmJJKwQirpe6NGFHpke5Euj9+UWky\nZHnwltLffb4ovAuVL7SAlBNTeSmsRezwSDL43Nqnm8Z6lqUh1ZsArR0wNuzG\n/Oh55hfSTaYvM73N6++s1sWu8oyHDBUemZVdy1vaM0lo+/mNlk1TlvBUGj9t\nw86XjBu0/MzGi9YQMDkQIZO6wfohl+xX68Npj5kEQjMlOcz1Ef7/CBVXYtMW\ncYrz1MhtOTnaFU1TD0YFKHKtLANwiKZLFYbYNaWL9+D0N0JE+pOQWmDW5lhF\nitnhQAfeBiTXhUjeUB3eGx8kBOYpgOGxbNbxFywYDwiNXIfxyOPSjnet1Fvi\nHxCLnX3M++wI6RDRicyW1HGJbCHGwT/iHZUio5OwuWijQrxBFfeug97fWnNH\n9y9H\r\n=7G2O\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC3Ro/w1J0eyxFufsu/E7ILIpvF4IrMoxxh/lL+xCFfTgIhAJvqM2KGnDScc3yBh0SzYXsHFVrC/WNDRgXHF3u0PsHn"}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.3.3_1586175737497_0.9116852861549998"},"_hasShrinkwrap":false},"1.4.0-rc0":{"name":"micro-observables","version":"1.4.0-rc0","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","prettier":"^1.19.1","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{"memoize-one":"^5.1.1"},"keywords":["observable","signal","typescript","react","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state management in React applications._\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value and that notify listeners when this value changes. If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\nObservables can be converted into new observables by applying functions on them, such as `transform()` and `onlyIf()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` and `useComputedObservable()` hooks. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n### Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.transform(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(book => receivedAuthors.push(book));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works well with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing state-values into observables and by using the `useObservable()` and `useComputedObservable()` hooks to access these values.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; completed: boolean };\n\nclass TodoService {\n    private _todos = observable<Todo[]>([]);\n\n    readonly todos = this._todos.readOnly();\n\n    addTodo(text: string) {\n        this._todos.update(todos => [...todos, { text, completed: false }]);\n    }\n\n    toggleTodo(index: number) {\n        this._todos.update(todos => todos.map(\n            (todo, i) => i === index ? { ...todo, completed: !todo.completed } : todo\n        ));\n    }\n}\n\nconst todoService = new TodoService();\n\nconst TodoList: React.FC = () => {\n    const todos = useObservable(todoService.todos);\n    return <div>\n        <ul>\n            {todos.map((todo, index) => <TodoItem key={index} todo={todo} index={index} />)}\n        </ul>\n    </div>;\n};\n\nconst TodoItem: React.FC({ todo: Todo, index: number }) = ({todo, index}) => {\n    return <li\n        style={{ textDecoration: completed ? \"line-through\" : \"none\" }}\n        onClick={() => todoService.toggleTodo(index)}\n    >\n        {todo.text}\n    </li>;\n}\n```\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with the `readOnly()`, `transform()` or `onlyIf()` methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n    received.push(newBook);\n    prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n    private _book = observable(\"The Jungle Book\");\n\n    get book() {\n        return this._book.readOnly();\n    }\n}\n```\n\n#### Observable.transform(transform)\n\nCreate a new observable with the result of the given transform applied on the calling observable. It works the same as `Array.map()`.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.transform(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n#### Observable.onlyIf(predicate)\n\nCreate a new observable that is updated when the value of the calling observable passes the given predicate. When `onlyIf()` is called, if the value of the calling observable doesn't pass the predicate, the new observable is initialized with `undefined`. It works the same as `Array.filter()`.\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n### Static Methods\n\n#### Observable.compute(inputObservables, compute: (inputValues) => result)\n\nCreate a new observable with the result of the given computation applied on the input observables. This is a more generic version of the instance method `Observable.transform()`, allowing to use several observables as input.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.compute([author, book], (a, b) => ({ title: b, author: a }));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value stored by the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n    const todos = useObservable(todoService.todos);\n    return (\n        <div>\n            {todos.map((todo, index) => (\n                <TodoItem key={index} todo={todo} />\n            ))}\n        </div>\n    );\n};\n```\n\n#### useComputedObservable(compute: () => Observable, deps)\n\nShortcut for `useObservable(useMemo(compute, deps))`. Return the value stored in the observable returned by the `compute` parameter and trigger a re-render when this value changes. The `compute` function is evaluated each time one of the values in `deps` changes.\n\n```tsx\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n    private _todos = observable<Todo[]>([]);\n\n    readonly todos = this._todos.readOnly();\n\n    getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n        return this._todos.transform(todos => todos.filter(it => it.assigneeId === assigneeId));\n    }\n}\n\nconst TodoList: React.FC = () => {\n    const user = useObservable(userService.user);\n    const todos = useComputedObservable(() => todoService.getTodosAssignedTo(user.id), [user.id]);\n    return (\n        <div>\n            <ul>\n                {todos.map((todo, index) => (\n                    <TodoItem key={index} todo={todo} index={index} />\n                ))}\n            </ul>\n        </div>\n    );\n};\n```\n","readmeFilename":"README.md","gitHead":"3b21634353226a6c82a8ea72fa55cb6a8a381052","_id":"micro-observables@1.4.0-rc0","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-MafRKTTusw/J+eUTX42ZwfX76z3frS0sJjiTakD/NJ6P6r3ZWPtY3Ou1fHI3CtRG9koAPezdkJoYbWAAEha+xg==","shasum":"53de9efbec62ac7002bd2e886105e0baa49cf9e4","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.4.0-rc0.tgz","fileCount":9,"unpackedSize":21529,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeqT8uCRA9TVsSAnZWagAAWo4P/2vW2Xm7ru52bdUXD1mP\nhaLSyc6L/Zi0hez22UJ4Pl0ZR2j4TOfO7AjxXevHspBIdCNYs7SdjlPBHGiC\nJzPaPMGyBVzwk5zHxzGIBZ1kPCXR2XGVND2vgIP5IGqU5+vtU6BCOdFjoz/J\nIRu7sHW9I3XEdkqFsxI6gHQ07L5WuWpVhCiVEMJobe7+cmT2EWgRntw1KO7X\njca9Idyr6/KV27bSypJwSw0S/n01pMdouhodvOTNmm98GxA3jO337Erx8CUD\nmkGGm4DimYJ8BQJMPypNG1sATcsf3OoPQGCc8YAySV3oXTntjUVYvvLXloLN\nLW/S++DpFhNW9qkdEuZNDOeP2ISLku7ETkI1tp+bktNjMiLGuku8Q6ZiaPXJ\nJLBedKGkBJfHvcIJrwzcqTTZQ3i5ii7/RHpvGKVWnIcOkFIrrzAdnIlvm0V3\nlavAltVHAn4lSgfi6v60t3rp0Q2sL2+8spIQChoVVz2C0d7qlnRWhr2DgUTH\nKLlvK80KiyX6a7fptYxlV110IekdYu7B8hLUBXms+lZRzpxvtQ567op+ywEO\nTNEVLqcD50ianN01xG6YGizjfCGZRE/I66BaGCYqrZaGGkjTDVqBjOFbsVmg\nqocfXmedygos8Gj06D65i4VnfM39MpM0j23CpT3X3ukFw6q6I+ZtL/8Bpprv\ncCxj\r\n=/GKh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDazi7/RHBHqH5njwllnS4gpVJNzfeb3PNXS+x6Hdi18wIgFhh+bzpidieur9LA+7r+Yn9qGVswzhdWgbN+3ICftrk="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.4.0-rc0_1588150061899_0.2724103156758195"},"_hasShrinkwrap":false},"1.4.0-rc1":{"name":"micro-observables","version":"1.4.0-rc1","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","prettier":"^1.19.1","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"45f56ecff338fbc2cfdf828d7b3720401dfbced0","_id":"micro-observables@1.4.0-rc1","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-VzV7I6PwF9gGpiZK/3qZu/8O30vW1qjZ2BaZ86GShjLjqDJfH0qEVYUJcLPmwzdZWMQRxpjd70NGzwADaO7NvQ==","shasum":"40020765013bb5f446b9b186317a56c31f2805a4","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.4.0-rc1.tgz","fileCount":11,"unpackedSize":26319,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeytoRCRA9TVsSAnZWagAAWkgQAI76BOemC6hBE4yS4wtg\nGQvQAyQ5zXQYqoRaFdSMRpeAIsD4J1zUzumSUWxnHrT0y+pQLLwW0jTcPyUY\n+JiZICFSsYfHUbIbnA4xY6e+H1LyDSWHfuYLSsk+KA/x4H0C/3ECx1WIW1DB\nDUwDrY9Ltui7IuHm4xc3nXzxq0XX+4je5OCcwpNNb1NviH9DKGrXUUb1/H+q\niwb8Wq+VihrIqT8HCbR9Gny95qLamih8iJrpbohh//4MAcgSBB9+y5WCd8L0\nxa3oOg/xgqiX5OS3ll/hC/Z3ACVeOK4vs9VwP6i6Qb1aS6cQVd6lWUGbAYCm\nUdoUTvteNedAVVvjXW4fIC2u1EFxBNiZpemhU3hHfCWE4Q8ika16pS/EedLy\n+chzg1H/cOc4eX6i4JOP29CnsM5o/vfvjCI1Xz7drCbx/qpv6MXTPDR1PJnE\nQvUGDo6DAY+GLBw9weg/9L03amIlEueAkTAyf9lV6bhVaqEK03aeRN2oV2pL\n2XyIBXHW4zihee0w8FhDkFXcfXaDMQyXzGhlt6M/aNWmtfT0VasmgIQfHQSa\nyndVssaIaMjmA08yZar++2Jh/ryHfUmDLgVEQ+QpUUTZOSCbOVJQl5exNiWz\nMSzFPI5TNWsdqG88RLOgu2LTeIyn8Q2ZtPsJpWkZDW5uATPHfp1lQ56Pl9Pc\ny9ww\r\n=wDTY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCklVkuNNUoqm6GKWaEX1SScNPJoKaZZ+c8ms6mzeu04QIgW0I4Ame17+P9WRP1AnnWVM3u5Hhx5IMsiKenLZZz7+I="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.4.0-rc1_1590352401327_0.8651600331293228"},"_hasShrinkwrap":false},"1.4.0-rc2":{"name":"micro-observables","version":"1.4.0-rc2","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","prettier":"^1.19.1","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"f27c5c5981e0f8ade7fe1d13d6ea977809ceae7e","_id":"micro-observables@1.4.0-rc2","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-jpuN4F8H/5q/bdM9PvmOfVb1cgwhiYnSTGNej+39EnWDpdyPzd1Y6L0bLQJkbL9LFHv8QROhmCRv3uKrle2Zxg==","shasum":"d595c15bd6446e822e32ae44bd5e24b2858c185a","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.4.0-rc2.tgz","fileCount":11,"unpackedSize":26361,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJezgDnCRA9TVsSAnZWagAAosMP/jGZBsNBgiiTVN7w/1QF\nqat/NFgWhlql7aJDh9hK7SD+XF5uOWQiNqGJMKAdoyh9hGLg8Q65MnkR6NWI\ndIPxiL6ZtVZ8kHmmiR+GBerLTkMSv+7r7W7fgU+ntxDeuMPfaNwRYWVWHAPR\nAwCggGYknhLw0yJc9bozAZ3daNU3YpIS2OGzq0jfpcEkh6jUb29wg1s/GEts\ncCEasZ4lB86sOHguiyMa9QdEBW3riTSXgGQ9YUtwqreyD61pKULCsfQ2yYYB\nm7Bz8mQujkCqJL+u6QV6xT6tZy7IXIHzen0/7uEQK2Hchxec1h9Wvm6gHMLn\nLtgHEQGo85b4E9KnMSfRYFI6z0bhEJUAZ0Esy9keEjB6e9HSjel7pFviwFwu\nBOCtl8ARiLGvDX+CHJtPFRMvYXWQD26/CVerlY6hjiv4t0SVKePjtFy38TTV\nKwm2P9A3egHghUf1LhsUqTpjLw4vqWXMF/ezQov21HkgMcFXcTMJjYvyJijS\n+Vdk+S7y/sP2CG57SPtXJdMxQEGTJtXHwZ6qJ51GDwCBZqK+ivrdFwFhyGHe\nFWsGtO5j/O6gtYWyOcv2o9nvFzu9QNEpGbBqtJczJh7/MoImL+3gSlt8dmgQ\n8YC5pA8AYXsU+PqssTGEmN7bPrD0ehWqy+HAM3LGCERZAOMkCnvOKUIgSHon\n5vby\r\n=Zs5I\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD/yfGtfTlhcK9+NwRLiC0k9KHozPUaQuxVYM7tBdE1egIgR9qenGZClGiQXVhItfwx6Hl4Vfb0/6f1V6e/uGMflXM="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.4.0-rc2_1590558951478_0.9924096443896058"},"_hasShrinkwrap":false},"1.4.0-rc3":{"name":"micro-observables","version":"1.4.0-rc3","description":"_A simple Observable library that can be used for easy state management in React applications._","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","prettier":"^1.19.1","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.6.4"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"464f5bb7313582e9b03c84115d0193254332f58e","_id":"micro-observables@1.4.0-rc3","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-VMy+zQCAABhz5POzDsFUtmjF/0YhElTHNrU27+B4w0kOO9SxgR0Y33IEseIv7oDoBWFRPt+RLV/iBkGrqyKFHw==","shasum":"0fac7395425276ce3f2c06c824128a06194178e9","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.4.0-rc3.tgz","fileCount":11,"unpackedSize":26372,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe4VDOCRA9TVsSAnZWagAA6BIP/2AbcrtPAqNe1TBKVv56\nXdHXOQeaHbC7MaAEgaMGzrOp25eopgpcGUPZdnGIfGS9CmePdn91O06CRf/a\nKmnUdZuhFj/rBkjZpF/LrsCcTo4K4lRni9CV7xshqcD7Ky9PucyJRU95NGl8\nC8nOwA6c5heEKnIjP5izavLqUJjd0QCht/l9QCJRmJfxCPaybQSVtbjMDa5X\ngM39Hkp8g4iPOh97ZI+UZstBsg0N5HOS0a5ccNuSjlOg8eYCI9wtdrnTvIx7\nOMHjNbY1Wshs7C5rCuOTXjx1UvUKeaOt+kUeUyWEvzMxWj9dWxYTldLs2l4d\nFlNormbWB171LxNnPXGZC43JUxLzBxWqtBHcFcWsGqj7WustfYf+T7E5AStS\nZVGHelRbgAjf9WkFjVQD8/nWk5pkNQlszxjT764LE5kUJW9wVE18HP41gZzE\nn4uitGIvfYI03Yyrv7kgIwcM5xdBEesqefEIfMAKwUbgYtAhwVxKdOZolF7P\nkUZT1G3VCh2F8RNJ8ezzZwkxoHNzKil36TwhcqQ6MSUzC3CUFQtG4OzjJ8zo\nP4FkwHNouZU+GcMPN+ojyAyMnuvc1yyTt3R3TieAb8WL4IitEmCW88BDjdys\nEdVS7ZHpDFkjdUToI0EZnYuRVVt6xEcoxChYnQbVzZQ/E7szndupdrOAHIVA\nvOIg\r\n=2N9H\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFeYSOOeAJoNVHSnUdzs0KxSo/OWpMrYI00q6gT5KnUaAiBbeAT2bsEJTfetY4t0Gc6l63/G1GUxfRzKGkuyWPG3cA=="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.4.0-rc3_1591824587161_0.6757568328390724"},"_hasShrinkwrap":false},"1.4.0-rc4":{"name":"micro-observables","version":"1.4.0-rc4","description":"A simple Observable library that can be used for easy state management in React applications.","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","prettier":"^1.19.1","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.9.5"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"891170e121b0d4c82d7b186fad0700b5376bff59","_id":"micro-observables@1.4.0-rc4","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-c/gJ/Nb+uG7bivIO+J05ATKIcnP1XO6eECwhgLqXuhOzz4xHkqueMZbcel/eY7PQx7I+WDI2uqUEL2Dx6+kIEw==","shasum":"552673a93ca207c53627b396b12c2840e5612ab7","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.4.0-rc4.tgz","fileCount":13,"unpackedSize":27623,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe8i26CRA9TVsSAnZWagAA3KwP/0LYAUvu20Eek9vZM3j5\nD+tH5L0NsYx66Ft1mPEwSFNqAafcyllF1hQvRSS5mTfrpWWoRqrZrZdTIzgi\n0yWW7067s0CtFMvUblURJIC3KMfYeuHzOtUAwJvbzZuKyzo1IcaG2odPCGlF\nCcPPayoNnMafuq+KSEUMA4DTtQm/szSmO/Kvv6i/SamTKH26pF0t+mRmqDnm\noUBfOOGKpcoY7vKtVPyEmqQCYDd5KlFS/xHZtdPEh96rlGXz9wbXR+eucJ0u\nW7m1qLbNfyMcdl4Zwz5bOU2opxcKMUsTYRRtd0zkKAqzxXLPQ8H18ttF32tL\n6PnaeBj/H2PwrckHFYFjcVcajgTGr1NAsQg5CeAh87jdjR5CgLdFLNEdfBvY\np0vbK/nP383ua0MuEReUO9g68HWRZNjga6VNJ5+xDvTZeFzmG2Godqy0uTSu\nLzMlmQxSYx56XZeBOuhEyT9TD4Y8o0xRxK0U2pTOD6KAwOk/ndRIAQbisyia\njcYMmn96WelLeiifZT4NN8DucpmKYeleXNAFhhgfz3hbTEp4E9EFjjEFDf1G\nOwAI7SVydkURSs16hnGso9wXVQuk6vuLQ74BhWQzxgyMC1JwLcJYmuUVDjHO\n6KLfaRtoVAfhDLzdQGYiHUQxR7e9vEVEFTn1VUPZ74fxjzP/U3WiTZSnxeDv\nmzDw\r\n=utmJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDyCfBpdVQD7YuUEr/Ch7NyrsW50Xec3/9iRS5NxLnf0wIgJO+lpaZMs1kg++2DL7r4eqJAqfoYWFegVmScONZZYTc="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.4.0-rc4_1592929721144_0.23570413095704645"},"_hasShrinkwrap":false},"1.4.0-rc5":{"name":"micro-observables","version":"1.4.0-rc5","description":"A simple Observable library that can be used for easy state management in React applications.","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","prettier":"^1.19.1","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.9.5"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"e7a001cfdb5b157e40a83830683b950c79ce7b93","_id":"micro-observables@1.4.0-rc5","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-+WlrzZ4DMxbjf6/Fem/nU0u4gHK2imTFrI6X9xp3jFkaRih4RrxvLI6xgazQpJkyn1n873KgRjS1pxkLxBhj2Q==","shasum":"ef2620877511f96b4f181499df672adbbbd0ebc7","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.4.0-rc5.tgz","fileCount":13,"unpackedSize":27649,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe8i/xCRA9TVsSAnZWagAAoLoQAI7/d5ubcRDl0R+Z+A+h\nbGNGsKnHLpSRDPfXyfMUBK3l+e/zZbeF19ivHvidA/jXb/kLvRwd1TtuyABt\ngWW4ro6+esbiNXTPK18cYNkJd7kZkwD7aNgoWKgkp02ButyBGoIeWfaLlRWT\ngtACJP14t/tqR4WgRf9XmaASH8R752nAroBXviTqReLfg78DE8gXln7cMIrL\nsg2zN0mEwdGiQfVAlPtI4kz9j6JHt0oa9W3GGu8REolX8AifAaiX3g+ds2uZ\ndJ8T4CvWrND6fZQskVAGhxewhglTRM2aAkmVFMrflySU3wlwwBUa4wDLzfql\nIudVaC7Tmu8d4Vt0/MAhilFa/Vpjx7bKmkrEjl5e0WHkO0bZgpb+0IDNamSR\n/Pfz5MOYDqtbeESyTyTqMrXA+g5whgsuL4ieK8P8H06mxkyY9emA5Ev/Apqo\nGySip//SdwBlT/ZmPMraXb9Bb76X/6oZgEXeYz1ytNCHn8gbYdH1sOMQBLX7\n/lpWacXwN0L2DKIUHOq+AhI9je/QJMC2vUJrdUWZmlgTY0UlmxZj6Ae1fHMc\n8CGqMG4HRa/DbmXd/t5bXOi5wJmLOCPdOz1Kf0S3eds2QmZQ7C9WmU+/UMIs\nhSKD+2MQQtoqN3bzs5yMWKCUzaOSNm3d3Q7GiQpR0BeOIprLiIJ8OFlyVm+c\n5nSB\r\n=rcSD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCfASU5nOpUcOESqJje3/1iPZn0hlzK0nryFnl/FQtIFgIhAPRwkxMJ6kNWvU3okPyprZp/ptUEUP5BVzZ8a/x6hXJd"}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.4.0-rc5_1592930288575_0.7123256200761707"},"_hasShrinkwrap":false},"1.4.0":{"name":"micro-observables","version":"1.4.0","description":"A simple Observable library that can be used for easy state management in React applications.","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","prettier":"^1.19.1","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.9.5"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"gitHead":"06b666e93b1e1caf01ef9de0eb8cc3bb3079ca5e","_id":"micro-observables@1.4.0","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-gK3ZTaMfTMU/BMU6+ar6iDeg/7bnSrDnLaAYEAzy54zL1IXaLps9BzXbt/SSaOXlh34CXQ3vQLbnRXfGkxsG/g==","shasum":"8be37ac64dd39cb1382aaf83b2c9c1b89c405484","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.4.0.tgz","fileCount":13,"unpackedSize":34927,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe9axwCRA9TVsSAnZWagAAFuIP/A4Kb5lH9FJp/QAn/aVn\nvewVr8Isvm1UOv6Vj8sLFlItcLO3+JouEHZpT8akuTE2Hsns1qZToDIa2fIN\nLvHqPqVqNVhteVeeQdpDvjl24ohzAiI5MWB5tgSSUUDxqLD8rmedTENm6Jxp\nxQ/s67tin2wotNdZmIUpp4MINuVA72Abi/N+BndM+MyoKuxAl+7TJTwQ+JPr\no6pclSlpulDYO5LvmhGkCyGfEuLVCkHJj+6s4pg3HUJzW7CbxrOGwMkC1kVP\nElzi+/Hga8OicvuKho4P47hXOdAxv84QbLZ1BsxPAY1S8STPWY3t3QS4/QhG\ncBRZNoqVA/fNzm8LXr21mk7kS3W+PnrVZKqaxlHFmng6H+XOrdO0anat7Kbo\nP6w/JbcUKuqGRmACreUICiKSto8wdL7ANprEVMni8sYD4nvIdflOXMl3PSj1\nVwUXKKD3VOIk4C2XGZbJnlu1cAMfs8NBmG3U2FlIZcpWETj/OMoKrPZVu2hu\nPpRiFPKqtBl4Xy8sKi8c3ODhDowozCexQ7AB8p6JInf01IoUyEm4E6SjeLL+\n2keIpGsl5930DiOlpfv0eZ6sKYSJudB6E1fI80CDfY/jWJm5hgNM+rrKDLSE\nvOfVMNRKhp1bgFujNdmcwmHsaSQQ31F6hOY6IOQ1xaEydnnKOP6oyg8APqWw\nBDP7\r\n=ZBXk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGX3y1TMGa4cKGxef73t1ezSAWHx0PC8PYlO865cjh3pAiEA5DacE/7cYQBcGGknNiZchTXNvOv9/PVfWhHeOzBflzg="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.4.0_1593158768240_0.5663700244234606"},"_hasShrinkwrap":false},"1.5.0-rc1":{"name":"micro-observables","version":"1.5.0-rc1","description":"A simple Observable library that can be used for easy state management in React applications.","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","prettier":"^1.19.1","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.9.5"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code\n- **🔥 Peformant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable.\n\nObservables can be easily derived into new observables by applying functions on them, such as `transform()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` and `useComputedObservable()` hooks. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.transform(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` and `useComputedObservable()` hooks are used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.transform(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos =>\n      todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo))\n    );\n  }\n}\n\nconst todoStore = new TodoStore();\ntodoStore.addTodo(\"Eat my brocolli\");\ntodoStore.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoStore.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoStore.pendingTodos.transform(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li\n      style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }}\n      onClick={() => todoStore.toggleTodo(index)}\n    >\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoStore.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `transform()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookStore {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.transform(transform: (value) => transformedValue)\n\nCreate a new observable with the result of the given transform applied on the input observable. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.transform(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `transform` function can return another observable. In this case, the transformed observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.transform(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => it !== null).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.from(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing an array with the values from each observable. This is often used in combination with `transform()` to combine several observables into a single one.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.from(author, book).transform(([a, b]) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable. This is almost the identical to `Observable.from()`, except it takes a single array argument while `Observable.from()` takes several observable arguments.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to store in the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block)\n\nGroup several observable modifications for batching. You usually don't need to call this function, but it can sometimes be useful for better control over batching. You can learn more about batching and how to enable it [here](#react-batching).\n\n```tsx\nconst location = observable<Location | null>(null);\nconst permissionDenied = observable(false);\n\nnavigator.geolocation.watchPosition(\n  location =>\n    Observable.batch(l => {\n      location.set(l);\n      permissionDenied.set(false);\n    }),\n  error =>\n    Observable.batch(l => {\n      location.set(null);\n      permissionDenied.set(true);\n    })\n);\n```\n\n### React Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => Observable, deps?: any[])\n\nShortcut for `useObservable(useMemo(compute, deps))`. Return the value of the observable computed by the `compute` parameter and trigger a re-render when this value changes.\n\nThe `compute` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `compute` function being called only once.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass UserStore {\n  private _user = observable<User>();\n\n  readonly user = this._user.readOnly();\n}\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.transform(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC = () => {\n  const todos = useComputedObservable(() =>\n    userStore.user.transform(user => todoStore.getTodosAssignedTo(user.id))\n  );\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n**Note:** `useComputedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating its value at each render. It will **not decrease the amount of renders**. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` instead.\n","readmeFilename":"README.md","gitHead":"27c5ddf35717874bc7032fd25fa2f28749a66895","_id":"micro-observables@1.5.0-rc1","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-G9b1AKjUV0Fw0px1+I9GuPP8TslM/7KZurZfYQWgI1HTSyMxkW7nAmaPSSJiFdC2GmTYIof0IQXsj/T6uuV60w==","shasum":"7f7cd92fefbf12cce113e0a2e9f94acb8ceee139","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.5.0-rc1.tgz","fileCount":15,"unpackedSize":38971,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe9hqHCRA9TVsSAnZWagAA5XkP/2AwQDtBgAOTS80TVCIj\nzYYaP4hHzS3J7jAeZL9CZndUwimQ3lEWmmX5WQASzBlmDNBO3P53nrv3kKeT\nLXQ9DkH6DbgrbF8QwnMVha4O4E2dRBciKUkbdw1YPPxU9kOOfcQctUEFC3K6\nj0wcdYZMAnS08NTxHYPTzD8qAaZyyCng1WHo2Htr/IxMU/4XDQbzriMKxpmw\nn3LqnENuz1nNC9Sf+jhTTpwasN6mD86/LbxEk7zvHDC9l+lqpvkN7cnKsleC\nH9XQpMfGo5QQkaDZNqd6GM8ytq5jpKIoseHQk+tEZrQ3CFf/89y6RhX7PWTS\nBK6HsV2rwCn3XE0YVXzQoS3UticCJlRAa3Dhh32It56EJupKwtXbU3CUGrPv\nqUkyQRkr3AFOw7t0iclXuMgVi+pueovN5WHo7SvJDPp1s+9k03f8vMjOOfH2\ndCzcgeMd33UA6lYX85TfwX9j2LKhfEJ7X9POJoU0KVXX9V0ymwOl3SbJfm3D\nUujYazhOuTuI5gBkehXRaXWrPqdb6oIT6dJAJ9lGBBowHtZu07pWsYfYnaAF\nQRARX7tbx72m6OS4PlIT/9lBv7hZGaqGXK3J6Kzigta9Q+rbtrfyl/mfvDkr\nNTJrh0dm8l+3tfSCjDvuSAZnNabJP5cZsJRvfhIu/vjJQ+fhKm9p4cLV0OoF\nDQqD\r\n=56xT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCRdVM2JsmxHWtwvFLTa0A7/F2iGtlBXn39pYoWiR0owwIhAML8SOrE44kFC4UjDTDkb7y6pS3dGk1b1IAlD3pAJH90"}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.5.0-rc1_1593186950788_0.661012462678511"},"_hasShrinkwrap":false},"1.5.0-rc2":{"name":"micro-observables","version":"1.5.0-rc2","description":"A simple Observable library that can be used for easy state management in React applications.","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","prettier":"^1.19.1","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.9.5"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code\n- **🔥 Peformant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable.\n\nObservables can be easily derived into new observables by applying functions on them, such as `transform()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` and `useComputedObservable()` hooks. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.transform(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` and `useComputedObservable()` hooks are used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.transform(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos =>\n      todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo))\n    );\n  }\n}\n\nconst todoStore = new TodoStore();\ntodoStore.addTodo(\"Eat my brocolli\");\ntodoStore.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoStore.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoStore.pendingTodos.transform(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li\n      style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }}\n      onClick={() => todoStore.toggleTodo(index)}\n    >\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoStore.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `transform()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookStore {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.transform(transform: (value) => transformedValue)\n\nCreate a new observable with the result of the given transform applied on the input observable. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.transform(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `transform` function can return another observable. In this case, the transformed observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.transform(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => it !== null).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.from(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing an array with the values from each observable. This is often used in combination with `transform()` to combine several observables into a single one.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.from(author, book).transform(([a, b]) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable. This is almost the identical to `Observable.from()`, except it takes a single array argument while `Observable.from()` takes several observable arguments.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to store in the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block)\n\nGroup several observable modifications for batching. You usually don't need to call this function, but it can sometimes be useful for better control over batching. You can learn more about batching and how to enable it [here](#react-batching).\n\n```tsx\nconst location = observable<Location | null>(null);\nconst permissionDenied = observable(false);\n\nnavigator.geolocation.watchPosition(\n  location =>\n    Observable.batch(l => {\n      location.set(l);\n      permissionDenied.set(false);\n    }),\n  error =>\n    Observable.batch(l => {\n      location.set(null);\n      permissionDenied.set(true);\n    })\n);\n```\n\n### React Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => Observable, deps?: any[])\n\nShortcut for `useObservable(useMemo(compute, deps))`. Return the value of the observable computed by the `compute` parameter and trigger a re-render when this value changes.\n\nThe `compute` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `compute` function being called only once.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass UserStore {\n  private _user = observable<User>();\n\n  readonly user = this._user.readOnly();\n}\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.transform(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC = () => {\n  const todos = useComputedObservable(() =>\n    userStore.user.transform(user => todoStore.getTodosAssignedTo(user.id))\n  );\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n**Note:** `useComputedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating its value at each render. It will **not decrease the amount of renders**. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` instead.\n","readmeFilename":"README.md","gitHead":"376adbaa8bd68376ae84e8d4cf0bea6abc63229c","_id":"micro-observables@1.5.0-rc2","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-CIAbw0PR+9GMyPytGFII+62fvAcv1NAzxvMkdhko+R5l4NZZXBheyJGrOaj5CbuAjXh43Y2goJGq0a7FJ9RdEA==","shasum":"2a19a909552d6d2ac72bcce78abd40c9f74036d4","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.5.0-rc2.tgz","fileCount":15,"unpackedSize":44525,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe9mdBCRA9TVsSAnZWagAAZoUP/1UjN05CPWEmfxqI8QDi\nHy4i9ac1cDcQZvQktqXoBna3nTew4Tp+ML+1Ow63ZGxxiMkGOc2uNXzPlFnY\nj/Wo0eEKPoAz04r0fLQSVJhh/7tRLt5YProQuAyoVXkCfV1gMHJqFkvtiT7k\nYiFkWRgr9Ue0exVG399oUgYE0cYF8iJ7eoNDuXym4FVk4EvWPBuq98xcyVEQ\ntnIZ9t2nXBj5hmIq2YVXxhNZDcRoHuABZjen/BUD1UnbpnyZo6Mvn7aSXoJS\n6oCFG/gs4h6chZxZC6VABXfCDcNLd6pbXvJdjgYkBOXDJIYEIthdR3hhpEeG\nJ6J+1qUwJELXXXG3YH8WUns7DxD7Oeq3FsmV1Ax6dlX/A79p9Y3jgovs+xnd\nYplNzckEtqIgT2X0UPrImMURXDdFT10EIEPiKhSiOhSy3MnG0IrWaPorwY0P\nfvqs3YonE1RtuemMHVbJq1PHWj0iVxCDykAX0CcF6wOgo/eMuXvIS8FvryPe\nnwEJDrRglvu3Gc+/HXjzOKnU3a1rO1FciFJFi30XnIAdlhdMm3SNnR8mDdCf\n81MFCbz+tmnvfSPCVwvRbG/xjFPyVi5wx4hyb+hitM871DNTbXpskCPM2wpK\njCY9DpgU5qKEU84v+/Rbbj5Ylh4cE/qXYENHpKcG29+JQfRGXmewx7e70xop\nMGZF\r\n=P7qW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB09Rxsie6EkRhaDXojml8obquLOoVJK54tuL+Tsf1RBAiAU8eaCQwKPpynn6wfqCVUJ0GEPyKl3YBDyshN3l4wOAw=="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.5.0-rc2_1593206593169_0.06524361953830593"},"_hasShrinkwrap":false},"1.5.0-rc3":{"name":"micro-observables","version":"1.5.0-rc3","description":"A simple Observable library that can be used for easy state management in React applications.","main":"lib/index.js","typings":"lib/index.d.ts","scripts":{"build":"rimraf lib && tsc -p tsconfig.build.json","test":"jest","prepublishOnly":"npm run test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.24","@types/react":"^16.9.9","jest":"^24.9.0","prettier":"^1.19.1","rimraf":"^3.0.0","ts-jest":"^24.2.0","typescript":"^3.9.5"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code\n- **🔥 Peformant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable.\n\nObservables can be easily derived into new observables by applying functions on them, such as `transform()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` and `useComputedObservable()` hooks. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.transform(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` and `useComputedObservable()` hooks are used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.transform(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos =>\n      todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo))\n    );\n  }\n}\n\nconst todoStore = new TodoStore();\ntodoStore.addTodo(\"Eat my brocolli\");\ntodoStore.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoStore.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoStore.pendingTodos.transform(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li\n      style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }}\n      onClick={() => todoStore.toggleTodo(index)}\n    >\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoStore.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `transform()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookStore {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.transform(transform: (value) => transformedValue)\n\nCreate a new observable with the result of the given transform applied on the input observable. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.transform(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `transform` function can return another observable. In this case, the transformed observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.transform(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => it !== null).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.from(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing an array with the values from each observable. This is often used in combination with `transform()` to combine several observables into a single one.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.from(author, book).transform(([a, b]) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable. This is almost the identical to `Observable.from()`, except it takes a single array argument while `Observable.from()` takes several observable arguments.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to store in the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block)\n\nGroup several observable modifications for batching. You usually don't need to call this function, but it can sometimes be useful for better control over batching. You can learn more about batching and how to enable it [here](#react-batching).\n\n```tsx\nconst location = observable<Location | null>(null);\nconst permissionDenied = observable(false);\n\nnavigator.geolocation.watchPosition(\n  location =>\n    Observable.batch(l => {\n      location.set(l);\n      permissionDenied.set(false);\n    }),\n  error =>\n    Observable.batch(l => {\n      location.set(null);\n      permissionDenied.set(true);\n    })\n);\n```\n\n### React Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => Observable, deps?: any[])\n\nShortcut for `useObservable(useMemo(compute, deps))`. Return the value of the observable computed by the `compute` parameter and trigger a re-render when this value changes.\n\nThe `compute` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `compute` function being called only once.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass UserStore {\n  private _user = observable<User>();\n\n  readonly user = this._user.readOnly();\n}\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.transform(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC = () => {\n  const todos = useComputedObservable(() =>\n    userStore.user.transform(user => todoStore.getTodosAssignedTo(user.id))\n  );\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n**Note:** `useComputedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating its value at each render. It will **not decrease the amount of renders**. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` instead.\n","readmeFilename":"README.md","gitHead":"e1b9ba201d9de6f02059df7422805fbb50e6f7fe","_id":"micro-observables@1.5.0-rc3","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-pSE33ViOKzij/fBYN4SY/w4ZSwDMXvxAD3Hl+iPE9bjw2GxUgoS63byftwwVMcottarj2tcQ9xKKOvCNK4IKZA==","shasum":"fde9ea351e6d1b9bca0a893af80912b742a87d42","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.5.0-rc3.tgz","fileCount":15,"unpackedSize":38774,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe9mjlCRA9TVsSAnZWagAAFgcQAKOY3B/UBCe4THTDtXhK\nXXJEcUXqSXuXJrNSdBVhIkDNu8VOtmeekdnT0BSkFp1eRz75aOHa57vm5PIB\nsfBpQrobvDn90JgZaGdF0Iq5gR2E+qTD1YN5/vCvppQ8Zeb8YgLkoyJ5NwSG\nAUskrQ9BVMm76DSCYnQaoFtIrSC2/Vub+FjkbXtwNAZda/O7fY9g4fH9wIqu\nqj9e+nat6OdfCZEmZ6WSYEn0ULmEHA81zuNm44kBDSujCefkW7FY9uQKpaYj\nTrDhb5mrLiYk+E6ySeiq2TO5UJ6r9EKwVjoOijmL1VbQwKliO0yIRA8jR9pK\nNVEq3CPGH1gr7cnYm4uFOh77Q0n/LT8In/sKeMFe2ZAoN/CgbDcdxs6wTYWF\njtgpr+n/mDY4Pni3I4kJJuGuMnU6Ebsp+B7Tnj5pVRAK9SchfosdP1Im2srh\ng8GL1hDj0xqdQkkeKydWvkW5ea7HXKhqn5gAvDCgl84vF0n0wn3MSbgBSnuR\n9CNuCfxBAiyOTinH8ac57p9w4lvIoSMAmtXmNjn8bLjTR8oiOd7jNGrfDt1t\nPm2Y0AbjwzNq2ckF62pVoHYciHNrDswpM5IKoGnDCFWro2WMXP2NjvTGLK2E\nzIhH569iLO5EDx5dH6mesirOjwEz9+RTyv523YEG2WX6WDrbwwysg0A7uhOJ\n4Lpr\r\n=8YDF\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFfUtRW76cYPhnz4MxYIdJAIcYxGohcnNnn0JvybghCUAiEA5Wpr4f8Jsac1OdlLr0auzFbdC06abyGtg/Lw27SQaxk="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.5.0-rc3_1593207013004_0.909925967824252"},"_hasShrinkwrap":false},"1.5.0-rc4":{"name":"micro-observables","version":"1.5.0-rc4","description":"A simple Observable library that can be used for easy state management in React applications.","main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"useTabs":true,"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.13.2","tslib":"^2.0.0","typescript":"^3.9.5"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in **6kb** production bundle\n- **🔥 Peformant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable.\n\nObservables can be easily derived into new observables by applying functions on them, such as `transform()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` and `useComputedObservable()` hooks. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.transform(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` and `useComputedObservable()` hooks are used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.transform(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos =>\n      todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo))\n    );\n  }\n}\n\nconst todoStore = new TodoStore();\ntodoStore.addTodo(\"Eat my brocolli\");\ntodoStore.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoStore.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoStore.pendingTodos.transform(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li\n      style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }}\n      onClick={() => todoStore.toggleTodo(index)}\n    >\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoStore.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `transform()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookStore {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.transform(transform: (value) => transformedValue)\n\nCreate a new observable with the result of the given transform applied on the input observable. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.transform(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `transform` function can return another observable. In this case, the transformed observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.transform(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => it !== null).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.from(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing an array with the values from each observable. This is often used in combination with `transform()` to combine several observables into a single one.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.from(author, book).transform(([a, b]) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable. This is almost the identical to `Observable.from()`, except it takes a single array argument while `Observable.from()` takes several observable arguments.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to store in the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block)\n\nGroup several observable modifications for batching. You usually don't need to call this function, but it can sometimes be useful for better control over batching. You can learn more about batching and how to enable it [here](#react-batching).\n\n```tsx\nconst location = observable<Location | null>(null);\nconst permissionDenied = observable(false);\n\nnavigator.geolocation.watchPosition(\n  location =>\n    Observable.batch(l => {\n      location.set(l);\n      permissionDenied.set(false);\n    }),\n  error =>\n    Observable.batch(l => {\n      location.set(null);\n      permissionDenied.set(true);\n    })\n);\n```\n\n### React Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => Observable, deps?: any[])\n\nShortcut for `useObservable(useMemo(compute, deps))`. Return the value of the observable computed by the `compute` parameter and trigger a re-render when this value changes.\n\nThe `compute` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `compute` function being called only once.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass UserStore {\n  private _user = observable<User>();\n\n  readonly user = this._user.readOnly();\n}\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.transform(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC = () => {\n  const todos = useComputedObservable(() =>\n    userStore.user.transform(user => todoStore.getTodosAssignedTo(user.id))\n  );\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n**Note:** `useComputedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating its value at each render. It will **not decrease the amount of renders**. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` instead.\n","readmeFilename":"README.md","gitHead":"53b411538e1c1db7ba5bee621fd3247ed3db46c7","_id":"micro-observables@1.5.0-rc4","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-VHkLU+z/E7H5+D214JxqGIpeff576DZkTRveeCE9So7GT/sYyjpvJ1nS2cIICxbfE8lB7UOhI3uT0i9Ug/gfVg==","shasum":"9d7126e0e53a1c7bfb9bc2e32f787ba1fff661df","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.5.0-rc4.tgz","fileCount":22,"unpackedSize":133709,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe+KRcCRA9TVsSAnZWagAAZuYP/iIBJyOH7h9oGsKqTTtd\nzphPq4LbG7c2ozKZyhaYpw3zzkhqDtiuPABvdRshFkt2BLe8HEF/HHcVPFkK\nYuS9ScLuG5jgakyo1vbL1VHOnZWQROrMySUYfgEqMPh1e9ULdqK8SAY40n2Q\nfV9gEjm6QbRDWpMrq2fyl353a4IcrAfJF8K4wdMfMqtR4URpQKQK1KhAEpmr\napHMyY66ADlTFriln8vTH9pRhyQqp1mmTYE3vrMtW+IJ4mEwL5RWY6/n/oe4\nLFDKGJcJOPFei4q4GbDpI8nGCmrHohgyTLhCxXz4FRuGeFlRK7YSTsCVcznS\n01/2bLPfAC6LPLDCvfB9sC0LKO5Q+RZwCAT6Zn4iPFXDGaInRKn08BrlkaDi\nRokk8Q/6B00ZZmBHGFnu20sCacTKPyz36jksJk0QnvKyJKBxyVkQNsDfCogp\naNhoBob7GGsLqU2tSOzGUqW2y4s7EcTd9JfNb3QLrN2ZtxH7slKpHuSkh131\nCVoHH+i1GZ5CIaiBFTOXrG+oZbmopJ/P7/ooK0lPEiyfpXqE5wfX+6JMdf+V\nJKtqBpagrpRV7iF+PSbjYWw+4KvfEdLkhkaMN741X26mMsy3t4BzNKMvhf3j\nHjQTi13S5b3aGpAZRzqXY3vwUFkciOD69vQbKTgkosDUB+cPZngDTTDNTa0X\nR5V1\r\n=Ihod\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDVZNR93Z4LpjCFByj6MvG6Be7Sapq6zRRuuw9EV0lZuwIhANDbaJg21f+4iQHPS8bJ7tPv0D69RESt5/v/gxDJnODP"}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.5.0-rc4_1593353307659_0.8460117606553259"},"_hasShrinkwrap":false},"1.5.0-rc5":{"name":"micro-observables","version":"1.5.0-rc5","description":"A simple Observable library that can be used for easy state management in React applications.","main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"useTabs":true,"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.13.2","tslib":"^2.0.0","typescript":"^3.9.5"},"dependencies":{},"keywords":["observable","signal","typescript","react","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Peformant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable.\n\nObservables can be easily derived into new observables by applying functions on them, such as `transform()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` and `useComputedObservable()` hooks. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.transform(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` and `useComputedObservable()` hooks are used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.transform(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos =>\n      todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo))\n    );\n  }\n}\n\nconst todoStore = new TodoStore();\ntodoStore.addTodo(\"Eat my brocolli\");\ntodoStore.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoStore.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoStore.pendingTodos.transform(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li\n      style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }}\n      onClick={() => todoStore.toggleTodo(index)}\n    >\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoStore.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `transform()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookStore {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.transform(transform: (value) => transformedValue)\n\nCreate a new observable with the result of the given transform applied on the input observable. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.transform(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `transform` function can return another observable. In this case, the transformed observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.transform(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => it !== null).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.from(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing an array with the values from each observable. This is often used in combination with `transform()` to combine several observables into a single one.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.from(author, book).transform(([a, b]) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable. This is almost the identical to `Observable.from()`, except it takes a single array argument while `Observable.from()` takes several observable arguments.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `transform()`, `onlyIf()`, `from()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used by the computation. It then registers these observables as input, ensuring that the new observable will be updated if one of them changes. If you are familiar with MobX, it works the same as the `@computed` observables.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to store in the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup several observable modifications for batching. You usually don't need to call this function, but it can sometimes be useful for better control over batching. You can learn more about batching and how to enable it [here](#react-batching).\n\n```tsx\nconst location = observable<Location | null>(null);\nconst permissionDenied = observable(false);\n\nnavigator.geolocation.watchPosition(\n  location =>\n    Observable.batch(() => {\n      location.set(location);\n      permissionDenied.set(false);\n    }),\n  error =>\n    Observable.batch(() => {\n      location.set(null);\n      permissionDenied.set(true);\n    })\n);\n```\n\n### React Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => Observable, deps?: any[])\n\nShortcut for `useObservable(useMemo(compute, deps))`. Return the value of the observable computed by the `compute` parameter and trigger a re-render when this value changes.\n\nThe `compute` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `compute` function being called only once.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass UserStore {\n  private _user = observable<User>();\n\n  readonly user = this._user.readOnly();\n}\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.transform(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC = () => {\n  const todos = useComputedObservable(() =>\n    userStore.user.transform(user => todoStore.getTodosAssignedTo(user.id))\n  );\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n**Note:** `useComputedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating its value at each render. It will **not decrease the amount of renders**. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` instead.\n","readmeFilename":"README.md","gitHead":"2af83eb490976d8b6dd3cc69478854164c8e4788","_id":"micro-observables@1.5.0-rc5","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-FI/cONnAkPD8NjS/cXtiVDw3aV8rlW4qhQwWD9M8QULWX0c++1Gw7pVwN52m+FnHFm0N9+XXu51zUkj50YJ1OQ==","shasum":"57b64e58f3ad3c6cf5781eb94b4a34711b0b2f6f","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.5.0-rc5.tgz","fileCount":22,"unpackedSize":135210,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe/yhvCRA9TVsSAnZWagAAjLkQAJVLjI43q3E2wJoi5b4l\nZv4UZlwhI1UUKoQ5s6YNA7uRu46jv9yo1dhno643CY67MVz6/bL/yQED/7Pg\nJ0x5f52sOqVTZwYUHyp3739WmToc0+1CcAY9tSVP6ZCCbZrPt9PRkD40+QVe\n3VskFiUaA+4bV4WfYKbZXIaWFGM2ss6smomE+8PyocA+wUmuMYU8jiFgVZVx\nQroU1jzr+9CmrdAXcw+ruGoG/8E7dzAaG7TpE1MM85LKBgOpy4AJJXRgta2r\n8+G3Fl8WtpwvYClIQwexMdqG2eLR17XSKEVPfp/6W0BLgXzCbv7g0UZFgiUo\ndF8Zca5exVcWMBgN1d4kAaXS0BahldG/IJgKRrctsTnddb+E/Bb6JY/nP4iG\n55Vy9rvTiWqELC56GgKQUNsbOJKDf8cgts2LOMmVhCW/TsCd4Cfl+8GlsDcq\nbp8hyQHx985a8CccMpYQI5qGjrXsvu7WjlLFPilQsxGoXt+MDMyb9eFjW7W4\nuj8QqQuOqahyewGgqWc7mSUe0Hbbx/4ud+ESJV5Va4KMTaiuz1Dewv9b8/Bd\n3C1vUREdAdUmDvsUD24iQ4CFY5Ak7KqClebFUyXEbsyetcErAaXSOFsYs9MV\nWCBx77AGmLGpmDG07HvjgPTDyYUdemn1GHUSqhyB6Hdlr6E0qOedHOrC+/oK\nRQHD\r\n=m+Vc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCJVHMbtsNelZceWxHZkc1iCopx2ePck16zNebBGAillQIgVY3hZuySnS52YGTG2Dr6+YZpjIPp8/p5pwAA6SuW9es="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.5.0-rc5_1593780334717_0.2913473034750138"},"_hasShrinkwrap":false},"1.5.0-rc6":{"name":"micro-observables","version":"1.5.0-rc6","description":"A simple Observable library that can be used for easy state management in React applications.","main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"useTabs":true,"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.13.2","tslib":"^2.0.0","typescript":"^3.9.5"},"dependencies":{},"keywords":["observable","typescript","react","state","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Peformant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `transform()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` and `useComputedObservable()` hooks. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.transform(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` and `useComputedObservable()` hooks are used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.transform(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos =>\n      todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo))\n    );\n  }\n}\n\nconst todoStore = new TodoStore();\ntodoStore.addTodo(\"Eat my brocolli\");\ntodoStore.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoStore.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoStore.pendingTodos.transform(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li\n      style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }}\n      onClick={() => todoStore.toggleTodo(index)}\n    >\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoStore.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `transform()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookStore {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.transform(transform: (value) => transformedValue)\n\nCreate a new observable with the result of the given transform applied on the input observable. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.transform(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `transform` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.transform(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.from(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing an array with the values from each observable. This is often used in combination with `transform()` to combine several observables into a single one.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.from(author, book).transform(([a, b]) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable. This is almost the identical to `Observable.from()`, except it takes a single array argument while `Observable.from()` takes several observable arguments.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `transform()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.compute(() => numbers.reduce((a, b) => a.get() + b.get()));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.onChange(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n### React Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => Observable, deps?: any[])\n\nShortcut for `useObservable(useMemo(compute, deps))`. Return the value of the observable computed by the `compute` parameter and trigger a re-render when this value changes.\n\nThe `compute` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `compute` function being called only once.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass UserStore {\n  private _user = observable<User>();\n\n  readonly user = this._user.readOnly();\n}\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.transform(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC = () => {\n  const userTodos = useComputedObservable(() =>\n    userStore.user.transform(user => todoStore.getTodosAssignedTo(user.id))\n  );\n  return (\n    <div>\n      <ul>\n        {userTodos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n**Note:** `useComputedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating its value at each render. It will **not decrease the amount of renders**. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` instead.\n","readmeFilename":"README.md","gitHead":"4cf7d8982997eb26fb115ee1226d72f5aea3bfe7","_id":"micro-observables@1.5.0-rc6","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-3KhMfpZzDuCq0f/YQmA3Maz66Mys0ew3QILuovA8chhnLeS8JMSi9BQQ6d6haK6eKeRNsQRN62cUbPMgc0wKpQ==","shasum":"bca4a4c23af8e8325f70159f1ba9ab3a4dbd3599","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.5.0-rc6.tgz","fileCount":24,"unpackedSize":132921,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfAuUdCRA9TVsSAnZWagAAASEP/0EINvXHJb1wBBTrzrbi\nOz+Wq//uH7SilV+eLW7ruPEwkQY1MRKR7fYBOeDB4sWrQAJk+z7lG0L0Ar1A\n2PdGz37a2W5TQJIJ2Ep8V3KLrsvshk/6WaqgtdqXS6PqpDBfr/h1nIjU3nRJ\ndz4j0mgCq3VsCRW5qwS7x62EJ7EFVhjI/roPEtwLzNh7uMhz8WTgvyy91b9a\nEDv5B+28WtQhlAGy3SIln/O+81tIZMwjkj7UDZS6NVCyym7z7xzNgdOm4Tsm\n8IV6LwpeG2EqjLxppuQVL9vkvpu9Npu6GwzWJsdE2AVSTg5hsLZIa0MuthWA\nY74+fzDSUbRtq2Df2mtQpEkpdq0CDrgLBKxIjfJshsYWLIOkUVJiK4mc8O/P\nh4eVMOdDqcvx2MEF2ocOWdlvPclB4lKWNS99Z2NFoKNbnEQw290QzjE/LSRW\n1eyhkAfPWg7G52M8kxfggqYOMN7aLvQnSFTTe5kdU+OwZmD8ZAHP0GbmnJt/\nbjsqsqEtuQWLNm7LbPpJetDnxWizZJUf8x8WD/wYrBXKQaKV2ZQA9KrlrQT/\n9zxY1SXbP8ltxwdq1JW0S7Sl0eHOO1BCZdVcaNNM8TgLnEFAl6PJpahdCcpk\noITjhdn8nXUix7+48vMgU8Aq7NPEBRqBE11BzVeg5LCATBPi4knwcPeghVc/\nm5gG\r\n=7Xw0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD1muVxRsRD9FpPFOgtB2MBYFP0eKpA1I/A8cMowdSP7AIgFwylf6QKWiB0eAsR654O+Bgeq9sb34CTerzIC9bGr64="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.5.0-rc6_1594025244595_0.23826241321305308"},"_hasShrinkwrap":false},"1.5.0-rc7":{"name":"micro-observables","version":"1.5.0-rc7","description":"A simple Observable library that can be used for easy state management in React applications.","main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"useTabs":true,"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.13.2","tslib":"^2.0.0","typescript":"^3.9.5"},"dependencies":{},"keywords":["observable","typescript","react","state","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Peformant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `transform()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` and `useComputedObservable()` hooks. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.transform(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` and `useComputedObservable()` hooks are used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.transform(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos =>\n      todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo))\n    );\n  }\n}\n\nconst todoStore = new TodoStore();\ntodoStore.addTodo(\"Eat my brocolli\");\ntodoStore.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoStore.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoStore.pendingTodos.transform(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li\n      style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }}\n      onClick={() => todoStore.toggleTodo(index)}\n    >\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoStore.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `transform()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookStore {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.transform(transform: (value) => transformedValue)\n\nCreate a new observable with the result of the given transform applied on the input observable. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.transform(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `transform` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.transform(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.from(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing an array with the values from each observable. This is often used in combination with `transform()` to combine several observables into a single one.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.from(author, book).transform(([a, b]) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable. This is almost the identical to `Observable.from()`, except it takes a single array argument while `Observable.from()` takes several observable arguments.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `transform()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.compute(() => numbers.reduce((a, b) => a.get() + b.get()));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.onChange(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n### React Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(compute: () => Observable, deps?: any[])\n\nShortcut for `useObservable(useMemo(compute, deps))`. Return the value of the observable computed by the `compute` parameter and automatically trigger a re-render when its value changes.\n\nThe `compute` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `compute` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.transform(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC = () => {\n  const [assignee, setAssignee] = useState<User>({ id: \"1234\", displayName: \"John\" });\n  const todos = useMemoizedObservable(() => todoStore.getTodosAssignedTo(assignee.id), [assignee]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n","readmeFilename":"README.md","gitHead":"dd0013d33e496458aa02ffa1df6df8a41b657332","_id":"micro-observables@1.5.0-rc7","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-/EehORI5DXhKklhOxHcmZ2xEK7V15BzI8OOw/DUNF77lP8pzjXjRyNFq52rMQEvUQP9AbuX8f/S+9WYh8J8vYA==","shasum":"1415a88e5f5c4718256bc553c546ecaa3163461f","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.5.0-rc7.tgz","fileCount":24,"unpackedSize":135073,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfAvu1CRA9TVsSAnZWagAAXEkP/j3Njo4rKmSyyA6kzZw1\nWFV7EAGOc/CQB73wme998kHSDoshHWOo1+WxkUxGry1GAgfpsqS8RldzSIXQ\nCK3qHgjAzIyW1iXruiUCnYcu7+xdu5tQTuRXWVPhFiZb/d3AmYDunx5jhzqu\ndOGN6FetcZpUAkpTPtEISAxr0WJDDQVo7La3vCwR9FkNyTJ9A0lBEJ9lnZ6/\nBUasvqccQdwlu2RdN9Ij+GRhfIf8/cY95sHHMqXrWo96GY+rvSlGMNW6w3Mt\n3E99nvwXqR2UfB8no0XNaupXMvAA1DEkYj/Qi2fRqnAP6N6qSg5+85V+rBbF\nNY/v3Dtw2QOTnnySnHlBpTi1VQ4C+//NnFLGJ2R1WFeE7KoDJXf7E/RLMnUD\ntutmOBVD3K60tOSPmvNGzCXqdleeW5yoyYvQjgZHl1ujEJS1sHVglXoHFhtE\n2dHgBbNXmTw7gonL16SYm7rfeMvS1Rur5SopGLYj8z789uzM9ljwb6HxHX2o\nk8Vdpiskaeg1+RllJQxls+b+pBDhUDBl5e/4fg3yJBlqnhSwMJqNNYFEIUV7\nUZKhL1G2mvVNo82ddQUJggsd/w8aUxqxqiVKve5914FpEA6bHsYb8/uFdgnf\nk5BsBpuLzHx86hk6QfSsTaDhrxYqBXI//zNAaBlR5t9+7x5AOdvhAAx2/VSG\ny/kr\r\n=5jbP\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCUPhakI7arf5RJognnc52Gp7J5vvzhNWPotVAHdYYAlQIgab9DqxQ58VkHGRlhwV/cS21mX0sDJKw6ifzbcRH7pjM="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.5.0-rc7_1594031028655_0.6184150464517197"},"_hasShrinkwrap":false},"1.5.0":{"name":"micro-observables","version":"1.5.0","description":"A simple Observable library that can be used for easy state management in React applications.","main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"useTabs":true,"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.13.2","tslib":"^2.0.0","typescript":"^3.9.5"},"dependencies":{},"keywords":["observable","typescript","react","state","hook"],"gitHead":"7ff0742172956dc69f46b1b6efad4b63898f8938","_id":"micro-observables@1.5.0","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-SWdAI8XXQoEpxV55wAdXaXUw6l+553Vr5SxYTQA7CCqUOk2CFBnjePDGXna3oPSjP8LxaJ1jb1wfC37zPvuuYw==","shasum":"22d35b0739d54a0e567472e1f3de246a09e63a67","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.5.0.tgz","fileCount":24,"unpackedSize":135071,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfN5MQCRA9TVsSAnZWagAABXcP/3jHfv6zuCPIxRpCkH69\ndFTnkYwlxsaWCgm52VHZsAldaYW+0TMtEtUmPTe3RVCtz7zrpuLmizV/nFtq\njc+6kpOQIr7jRL+DxEH6FIepBFCHPeCoAUfNltqAXjYhiO+YaII8+m/Z5jrN\ni10JzC+44s32y3E1JihbXDYmKO4iWfonmwAIRkHfvstXnFAtJdtvNY6qTc2H\nVZJJ0OHSdoNC7YhgMzzYIsICGWQ7jxXTBc72EiG4brsLq9TKnqqxLrYWSRQv\nm1mJQxwiH3jbVPDn+KpdmxykL6L/TXL6tUqmRtkOxJoTd0mZwB57LMbwaK9H\nGygu0DmX83xAVkcTS9Zn0lkWA8Wd19nCwJesv46v6DFC+rPNj2GOZSajh/er\n95ave7Kf8tTkL875x+cUl2ke6AP4yPQYnXVOn0GsquamF2q3xsf93BHCTOqT\n/368SywF2QpECrj/mLd+XajzxfzaOlAOdZGVp32gBrW2vbaOS6gA4UGN446W\nvOqoOt25VDifcN+ilwmdnicK8gJL5tEocXWqMY3tRRV6OQo8mQPU6ybXBmPT\nkbIi4PhW+3ggDOXjxb/FLEiXcXLC2tGtm6NreLlvqc32P2GHXU/YP5p/v77r\noaStJlpUCLz1lKcsFiZSeLh0qH80jsUdvhSikFEf/bHvix7/xWKtrf5Aa2C3\nquxD\r\n=FeL1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCXhJQdSaQ2XNadKH/sGKOsPZ3r0lE7ardK/Xcr48onVgIgaucqYtJ/+nlOJ52COgTI9HN9/8ubPps6RBtSEpGV8qU="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.5.0_1597477647535_0.9779803273558481"},"_hasShrinkwrap":false},"1.6.0-rc1":{"name":"micro-observables","version":"1.6.0-rc1","description":"A simple Observable library that can be used for easy state management in React applications.","main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"useTabs":true,"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{},"keywords":["observable","typescript","react","state","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `transform()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` and `useComputedObservable()` hooks. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.transform(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` and `useComputedObservable()` hooks are used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.transform(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos =>\n      todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo))\n    );\n  }\n}\n\nconst todoStore = new TodoStore();\ntodoStore.addTodo(\"Eat my brocolli\");\ntodoStore.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoStore.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoStore.pendingTodos.transform(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li\n      style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }}\n      onClick={() => todoStore.toggleTodo(index)}\n    >\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoStore.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `transform()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookStore {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.transform(transform: (value) => transformedValue)\n\nCreate a new observable with the result of the given transform applied on the input observable. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.transform(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `transform` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.transform(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.from(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing an array with the values from each observable. This is often used in combination with `transform()` to combine several observables into a single one.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.from(author, book).transform(([a, b]) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable. This is almost the identical to `Observable.from()`, except it takes a single array argument while `Observable.from()` takes several observable arguments.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `transform()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).transform(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.onChange(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n### React Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(compute: () => Observable, deps?: any[])\n\nShortcut for `useObservable(useMemo(compute, deps))`. Return the value of the observable computed by the `compute` parameter and automatically trigger a re-render when its value changes.\n\nThe `compute` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `compute` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.transform(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC = () => {\n  const [assignee, setAssignee] = useState<User>({ id: \"1234\", displayName: \"John\" });\n  const todos = useMemoizedObservable(() => todoStore.getTodosAssignedTo(assignee.id), [assignee]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n","readmeFilename":"README.md","gitHead":"0007827a3c55be7a4c2ff0ee78205c598dbe7003","_id":"micro-observables@1.6.0-rc1","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-Y08ax8u4zpe4PmRYvh6bmVQFouWRNE4jQ5gfy3Ok4UCPl/AHtkRmQgzDa2e/hwssMPid432UBIdmpV6cGg2FKw==","shasum":"5e4ae3607d067a60e26ca2df8f1bd3f65621d9fe","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.6.0-rc1.tgz","fileCount":24,"unpackedSize":137449,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiaeACRA9TVsSAnZWagAAT7sP/1wjVZi5PWgE5+2P23qH\nS4QSgrce5sk4+f7H04MYdDj/LqCjrFJfY0QGQnXmT0rfXQR40tFbOEOLRZ3h\n8SRuko/byx4+TCGEY96aW5B9+mJA8FnfeFtrfvrIq5T//lDkgJITkiWZHKdn\nuz4WdaU2A0rSTxPcINRq4cFaZzlaoRhOaSXDmeBXxjXQASxl7IuPBxSynXT/\nSZVFHYeNFd3A4Scutx9BTT6rnszxOckmEpQ/1lOGFLIwGY6izvCfYYGzbHWl\nr3Fy49s9IYaw5K9jOmTSio0YYESyvwmocUu8ZDOU7G78O95J1hkfZQcWL561\nJFckZOx9SK6VpbZ7R1kD3uNqO+Tp9V1J1/7Sr3x3Sb52AkzfCHCVDBceBoPg\nEAl9yTux0xqxHVl0KMmq3w81ru7QiRb9Rnj5CjYH6RJvtDLBcidPnTsjD3fB\nVDmuGb/wBwdzit+rPYTvp/zTQg4ImUsUI7ANeq4LE8ehBg1owFdL/+J9FJO+\n3W8RyjLIDXy/p68WpmYtbbyCvQWPJdbOlcxFVrFmSV4JYYoL3h8EjDT62CpD\nEVjC6X4whJZZTMzHRaLnlhp8eYYNgwWOGhXKLwFgMJXYPU2r/PPuEIB/lV9T\nLfMuMsuq2ckITyAO0dOhq28SDhsjpawhaZxWUE/f/tuFJZdhElShMxbD1U1h\nMF2+\r\n=VLpR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEh6cYBD5iqIynirHOfQFNLso+HEYcfiIkky1JjvFuBvAiAWnKCjflnr+DM1uAicUD6FmMGECkZM0pI9HmsuqubnpQ=="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.6.0-rc1_1602856832361_0.27355142691995527"},"_hasShrinkwrap":false},"1.6.0-rc2":{"name":"micro-observables","version":"1.6.0-rc2","description":"A simple Observable library that can be used for easy state management in React applications.","main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"useTabs":true,"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{},"keywords":["observable","typescript","react","state","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `transform()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` and `useComputedObservable()` hooks. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.transform(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` and `useComputedObservable()` hooks are used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.transform(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos =>\n      todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo))\n    );\n  }\n}\n\nconst todoStore = new TodoStore();\ntodoStore.addTodo(\"Eat my brocolli\");\ntodoStore.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoStore.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoStore.pendingTodos.transform(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li\n      style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }}\n      onClick={() => todoStore.toggleTodo(index)}\n    >\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoStore.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `transform()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookStore {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.transform(transform: (value) => transformedValue)\n\nCreate a new observable with the result of the given transform applied on the input observable. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.transform(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `transform` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.transform(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.from(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing an array with the values from each observable. This is often used in combination with `transform()` to combine several observables into a single one.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.from(author, book).transform(([a, b]) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable. This is almost the identical to `Observable.from()`, except it takes a single array argument while `Observable.from()` takes several observable arguments.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `transform()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).transform(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.onChange(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n### React Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(compute: () => Observable, deps?: any[])\n\nShortcut for `useObservable(useMemo(compute, deps))`. Return the value of the observable computed by the `compute` parameter and automatically trigger a re-render when its value changes.\n\nThe `compute` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `compute` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.transform(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC = () => {\n  const [assignee, setAssignee] = useState<User>({ id: \"1234\", displayName: \"John\" });\n  const todos = useMemoizedObservable(() => todoStore.getTodosAssignedTo(assignee.id), [assignee]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n","readmeFilename":"README.md","gitHead":"66f564c59e82be077973ff65addb12f77ef06696","_id":"micro-observables@1.6.0-rc2","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-5zqrzsNt12V/GbZ+W+eqQUGLuHcCE38/Nt4O9Uhi5Xqc0xj7hYo0CgKSOMi7PLDUzHYZYbJjeEcL7k6ivVdlpA==","shasum":"eb95838526c89392f81143e5750330e0feb1acaf","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.6.0-rc2.tgz","fileCount":24,"unpackedSize":137483,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiaxQCRA9TVsSAnZWagAAuTAP/1R1ALrcal2W1dVjmmw3\nrVsLoT2fKHMFNreGMQ4hmbg6jDdwxlUy9KwBAFWtzkqjvDWDKZpsDKbiLAoQ\n158h12Q246GUmrPkdujlr1mbE93adJM5IlPlX3Pfq43m/+HvJxZff9/hauVK\nnRGdUsjKX2V7CDbyCHotpL0665wGYfnnUiuBfWR2wl0X3nuqZeF7EdQB4Yao\n7UOvyde5+34JRt6PeX5rF4OwWhC28sctO8GE+PByYY1z2UUPagts+B1ughoZ\nYSHAL2uGk3j+jyu7/jl/hiG7pxVUOYsVpGCjIuf1Xnag2Ibxz1LKp25LeAKF\nHyLqtRPgPqcJeuuKfPgk5QatjH+m71mstgzts9T0uHSDZzM7CWsuCQZ2Oni4\ncNDV4EsXWCbYSdhVZaDkHhkkoUmD0NdfXoN7Gj2Xikzc3il/YB/ZUAuxrihN\nc5CWcblIMoQTGYBnOR8sS1PHyJmhMgTVBISoHK78Fv88SV8V8GpQaKteWWPw\nKEENa6LYpKIcbDhkQKM91qvD/iFbz6MZZ4lMhsO72DRzJ3QiIgcCt4sKW080\nTgmwJpDnud4yjCdZ3y86QtYnecR9dBXBHSmCf1BMcJHUoMbkEkxdw2Eyfsg7\nJm+LNkqcnB4kINAlj0SewHbIbGT3y2+R714Md6V8htwDKXzUR+n80ZCujClS\n16kn\r\n=ieqZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCTc/eUMRvveikYa3qB4fEYwmGH0MKHGLTCU1WYBSSKxQIhAOX5cUF0V5bCapzPN/DAjPD9/KmCpRKcGWG0Gr1ueeCK"}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.6.0-rc2_1602858063753_0.6322621057946134"},"_hasShrinkwrap":false},"1.6.0-rc3":{"name":"micro-observables","version":"1.6.0-rc3","description":"A simple Observable library that can be used for easy state management in React applications.","main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"useTabs":true,"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{},"keywords":["observable","typescript","react","state","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `transform()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` and `useComputedObservable()` hooks. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.transform(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` and `useComputedObservable()` hooks are used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.transform(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos =>\n      todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo))\n    );\n  }\n}\n\nconst todoStore = new TodoStore();\ntodoStore.addTodo(\"Eat my brocolli\");\ntodoStore.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoStore.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoStore.pendingTodos.transform(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li\n      style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }}\n      onClick={() => todoStore.toggleTodo(index)}\n    >\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoStore.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `transform()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookStore {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.transform(transform: (value) => transformedValue)\n\nCreate a new observable with the result of the given transform applied on the input observable. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.transform(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `transform` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.transform(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.from(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing an array with the values from each observable. This is often used in combination with `transform()` to combine several observables into a single one.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.from(author, book).transform(([a, b]) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable. This is almost the identical to `Observable.from()`, except it takes a single array argument while `Observable.from()` takes several observable arguments.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `transform()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).transform(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.onChange(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n### React Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(compute: () => Observable, deps?: any[])\n\nShortcut for `useObservable(useMemo(compute, deps))`. Return the value of the observable computed by the `compute` parameter and automatically trigger a re-render when its value changes.\n\nThe `compute` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `compute` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.transform(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC = () => {\n  const [assignee, setAssignee] = useState<User>({ id: \"1234\", displayName: \"John\" });\n  const todos = useMemoizedObservable(() => todoStore.getTodosAssignedTo(assignee.id), [assignee]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n","readmeFilename":"README.md","gitHead":"1e1d8208b26dddcebebf05c809472bb8d4cf116d","_id":"micro-observables@1.6.0-rc3","_nodeVersion":"13.7.0","_npmVersion":"6.13.6","dist":{"integrity":"sha512-mUCgA1135B78QpY5BUBqNBk9UmhWqIZOXD3DUU0KwYuCemLEvUZvu8yoczQ2g3YnlvBon/sMBMWKnKfTr8ctgg==","shasum":"655704da9f2e8c0e3d6e56f5f1d398e42840592e","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.6.0-rc3.tgz","fileCount":24,"unpackedSize":138713,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfjXIGCRA9TVsSAnZWagAA4hMP/A0eeoRU3m6CLHRvbXbH\n1TQ6MNATsMgcSQfFSnBOeA2kl4joKdEpBrmn8cW3WQO++PPI4Jd2wVDfOhKA\nuTokyDlbzENuinKurFa0VMLF5X6WHeKburssCLG4d7ChyczJBwn2UIstieTE\ngA/gNApu9JnteGGppU22g35R2ocgt1VqslaYtAcp6uUTcYYYpkDlUX2+HMLm\nheNSX53tFgPkSb4jOJUswwyln4xBP4DOrrT19URZogGg8RgrZkcstbqUIOq6\nn2Cv/sx4vrqDwaIkcwfLoS6Ge9Qo3cMA26T7ViqkUsNr5immJD/xxASJJPzk\nMnuqk7OuJBHZ+3Oa5uYOhLjeuKtacVoHjv5O9T8JI/4/S9btGo1Ct4OS5moj\n0l5El1lgwsM+xzb67HJ1T3aeMWwioOpLE/8QmuUreN8gKdeLtbIbAa9+T1jh\n7Wo5Uu1eWzWoVapicWuH/U2KIEyiWFzz5Mvy94krsZQ3Uibxlg26lPtiy1FU\nCwBACerzfmV5eWVkQE2R5qxd6Bsekodpu4wXChrGWKBUCPW0DnQjcTOD7DST\nX7q3srTP9dRCDaCKug+ElYsNmVkJGFbkytys9uK3m3HfllTgK5xdDGyVzxg6\nBuinnDKjKtkXrHRYL9qMN8BtvzXe0PtG0QTpevGhXC+MmKGl7G7hvIlhREzV\nyjzG\r\n=CiHu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB/XC01An0MxVZMH2w49v8nuMjPx12rT/6hd30MlA98mAiBaeunbgd3AFi372J9HFrMupP56nK13Y212EJXFqEa8yg=="}]},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.6.0-rc3_1603105286029_0.08802078185407369"},"_hasShrinkwrap":false},"1.6.0-rc4":{"name":"micro-observables","version":"1.6.0-rc4","description":"A simple Observable library that can be used for easy state management in React applications.","main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"useTabs":true,"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{},"keywords":["observable","typescript","react","state","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `transform()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` and `useComputedObservable()` hooks. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.transform(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` and `useComputedObservable()` hooks are used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.transform(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos =>\n      todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo))\n    );\n  }\n}\n\nconst todoStore = new TodoStore();\ntodoStore.addTodo(\"Eat my brocolli\");\ntodoStore.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoStore.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoStore.pendingTodos.transform(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li\n      style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }}\n      onClick={() => todoStore.toggleTodo(index)}\n    >\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoStore.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `transform()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookStore {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.transform(transform: (value) => transformedValue)\n\nCreate a new observable with the result of the given transform applied on the input observable. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.transform(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `transform` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.transform(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.from(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing an array with the values from each observable. This is often used in combination with `transform()` to combine several observables into a single one.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.from(author, book).transform(([a, b]) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable. This is almost the identical to `Observable.from()`, except it takes a single array argument while `Observable.from()` takes several observable arguments.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `transform()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).transform(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.onChange(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n### React Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(compute: () => Observable, deps?: any[])\n\nShortcut for `useObservable(useMemo(compute, deps))`. Return the value of the observable computed by the `compute` parameter and automatically trigger a re-render when its value changes.\n\nThe `compute` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `compute` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoStore {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.transform(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC = () => {\n  const [assignee, setAssignee] = useState<User>({ id: \"1234\", displayName: \"John\" });\n  const todos = useMemoizedObservable(() => todoStore.getTodosAssignedTo(assignee.id), [assignee]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n","readmeFilename":"README.md","gitHead":"22f5fc04e91d8ead0af3c383b945473d7a103a0b","_id":"micro-observables@1.6.0-rc4","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-/RJaYNBhxOB/jQL39OSNu0pX2al1ch1jmkAKOEWhUqeZiQL7v+haHxgRRAwVwZ4oCXOJC+TVdP0AHNiH2aLzLg==","shasum":"53e0c2aa36c4823afa18d1f6c0edee79f3176fa3","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.6.0-rc4.tgz","fileCount":26,"unpackedSize":152601,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfv05RCRA9TVsSAnZWagAA3NEQAKBeFH3u4DGUxLTgnptN\n5dhr8TdPceJRG6v6jCF/4f/QU57cLgfD/6aLulyuo0ZB0wVH0B+g06AsKFMn\npH3ihiTrEvte9qxNR/ghcP+N0NI4y/LTDtiW1nX4GPu2VwX35da3lB/0n6lD\nRITiIvA2+b7xAp6Kkvq7ZBhMaVli0iGeR9OUKEG3/MaeQdpmZaFHJ4at1zGk\ndBmxG2+jTIC6HxXW71Ak510BC2/CdmjHq0zZ0eNEBatLmmoyR2XFjsHna1HU\n6GUaDDPqeXE1WKE3ievILE3CCunHa83WhzbqTrqZ/jGQS8sra40QhjsiRT1s\nC3l6HZgPD1wvj1WEJCV+iFtyPzdJfX8ahDYsNFxLDHVTbJ/GIpQMEq85mBBy\n8AWQ6aPgJywr9nt43txisNYPOv7Sx9rklT13zvnAjBcTcGEZ4wkvBQ//ogKf\nDPHDXeBbQc+e4LjB2husZxmuVZ5v48626p2V2J82bdR2HhpyjhMJDcLGME49\npKNjw+hZOtTk2Nwwdls++LnOqEdRNxsOPwtTSA7ZyhaWA2OaOzzYoKB9SdKF\nlJpdsCKK/ND+ptUWdJxdvgJ1oaJr7312vO9/ICrzWXubPtYDAXfMhZ/51MRR\n4QtmWbV8mBTxFOBGxLXQG7F/cT5ZFFM/WZvpA/a8/WGoeJpCwel/AZ+6p3e/\n/wQX\r\n=jSVa\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC+0iXknwTVvF0yg+Ufk2XhOvhjWSo4scmdehzqDc+vXAIhAP06UKKfLfsIfJKf+RaBrr4nSQEYlxrtMRh68YDmzzx+"}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.6.0-rc4_1606372944971_0.5841690371112549"},"_hasShrinkwrap":false},"1.6.0-rc5":{"name":"micro-observables","version":"1.6.0-rc5","description":"A simple Observable library that can be used for easy state management in React applications.","main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{},"keywords":["observable","typescript","react","state","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.onChange(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"863812eb8255b339de7905904cce55a741b82c65","_id":"micro-observables@1.6.0-rc5","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-3GIV2e6lLQAx+MVffktiwOG7WPYHVI733S3yhgsziwfUceEcbPvuMu/49MWXQQhlxNc2zKN2/CMx2Od9dVlU1w==","shasum":"9d02df697feeaa0a82b45b866f2ea872f5ae52b8","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.6.0-rc5.tgz","fileCount":28,"unpackedSize":158747,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfv3l+CRA9TVsSAnZWagAAqowP/iIDxUDDR2O2fgwCK08c\ncoP7ervfy6/P2obELK5gt98Q7nLH2X9/ounj7jA2R5gHeRbHz0Ia7MzqBIeY\nP1X4WaeGOUqOsBy9A6Rr1eMU/ro4WGCFx9i+uCZCAHY0BhcJjzvwGKncgHy9\n5Wl3tuP4VtnBnYbqlrz2U2cFTjtZ8SlePe5D3QmCXqG+sW2g3+tHOCBwUpsv\n4oWVgOPQhT/xK2/TgmpGhycLIbbvW6qKDBpojUeksv32YkImXC11kAz0n9Th\n69N/dMrkQ6QM6IZRjAJksIvY81zogCLekjMM74FQ0jYV9uMfjY+mWgDmTdZv\nCr2gw8cPEEZsVa5hKbytmtW1GcwrpIKTTruiCHFmQJD3XcauZ/uQDFvWCger\nFiOv2mOy514x4fHgTFZDwvKwMVH/NcDuEeVom5U1Zy+5O4kj4whe+ysMzjb6\nbAB86OG3KHpy+6FdtoMOB/oYTxnB2xS3gURFgg3VxX+rubnqyJq6P08/asBJ\ndjkXALLYM3SbjpnPu9zhQeZfi8//vYBRc9DALevnr0WgAV/cz/fZBDVJ43Cq\nEUKZ2lhLsofhYPtiyi31RMtyW+xx2VAFBY3ejW2qbWTGAfktu3l9lvqLAA8W\nuI57nK+ddCCtHd/ukv5Lb623K/yGJKnaPVb2xVGHyXPUgXNLee8y3nXHt6uQ\n0MiM\r\n=Kajv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAogAUyl7l2JlXZjbyuqKSOnzpmaDu7JSKD+/qlIc4HnAiEA2KIa+mbptjV+cU7jIDiZ9Xj9sgFYg+0ZyKLyc2PAp9A="}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.6.0-rc5_1606383997866_0.2424106789689051"},"_hasShrinkwrap":false},"1.6.0-rc6":{"name":"micro-observables","version":"1.6.0-rc6","description":"A simple Observable library that can be used for easy state management in React applications.","main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{},"keywords":["observable","typescript","react","state","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.onChange(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"3485751d2343e54c74e1a456ed226a1617fe39d1","_id":"micro-observables@1.6.0-rc6","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-60hRwjDGSvvEMiip/VnReKdkGPZTriM5yib/lPW7j7Bn/cT8P7ztEZ39n1/Ga4y6Mhiq2z0rtR+q7Q9K9qTXAw==","shasum":"2d4403adc496e3a5ea90d6d23194cfeb6a987aaa","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.6.0-rc6.tgz","fileCount":28,"unpackedSize":164933,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfv4EbCRA9TVsSAnZWagAA7jAP/iG0uS4swc14OYpWMpjN\nCm1OFT4SU1W40EyqxSZWezZiHZS+sOAynjAqxgKh79KfqGKyRSfcUfkXt7CL\nuelc+zbBRq0ryMs7jUeHbrUUtJuLRYQ7Z8dARclvt9DS+e7Fro2h2KkrKMqF\niquirE0SKneYRJk1LCusEPBnLlOnOMIoUFAbwiVMjOVYpKIrajlpG8AOIUxn\n3H6+0asHhT1xpIqUrDO1bM7zqReIM7lTDwJ5Pt8kef8wUdtp+Jpfq3YPzclV\nME5WQ1L5Px/1KvyZVJADBjM3zPS+oe8ZlylEf59Y+gEF1SoTpFuoUZTSrHbf\n6D/a6chV7oQo8Ci8UcW81Fb+4yr8WdRhhiUg3Opbt3esLn7MuRFv0eoSToy7\nuyU8NBfjSKAG9jN1Y7YRn66j4+QmXro9ZOvVSqZ1LKbJ6tCMkHzz5iRud3NZ\nEHPKiDfhHWPrygs06eeCkIjg7liGZHa7KYK5qlQIVdkvtKJVGQMKGv8Z/NEO\n4L9DD50tfZ0t+MeZYRrt2Dh1SGIG+In5JcUTjUKi31q6i8Rs+8zptd1QssXY\ny3tmODqGsUwCpMj4zjLF5u78kQJ3AX57Hdakxtjs900N4w2P1rO+2GYZCaIT\ncVKR5XiJwK+VALS+oWoMYEoTSc1oPFXupvNdc1tcfqOxyHMgViOuJLUbeLd9\nJYAQ\r\n=1Qi6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDk4MK8tAXI3jyT3bn1zyplJ4l+e94a2P7JNCJlE3GAzgIhAKkL0Ol6szHe5yRpeseSIL4CKFPqnxAmQcoIQDO+eNpi"}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.6.0-rc6_1606385947482_0.8965793895991367"},"_hasShrinkwrap":false},"1.6.0":{"name":"micro-observables","version":"1.6.0","description":"A simple Observable library that can be used for easy state management in React applications.","main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{},"keywords":["observable","typescript","react","state","hook"],"gitHead":"8c0b8292360de1d5399e2a55ee6cea68f6effd70","_id":"micro-observables@1.6.0","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-tCUHPDcJyF4qgPf5dBKra0QPFAfdF/batUkpVDiyckWEC4FHM66gUpNTW+nzFe7lZTDGOZS7a3EItGrNyNbgYg==","shasum":"8a9ed894f69ba5771fc661738b308ca9b70c7e1f","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.6.0.tgz","fileCount":28,"unpackedSize":164929,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfwCiGCRA9TVsSAnZWagAAM5QQAJc1RXW1BopsA8fQ0qyU\nSYD1cyrHAfKUr0FGlYL9V8Gq65HldPz59j9qkgLtktPcWX3d07mbqswE9mjT\npquO1/9GUti77VcQDQroTI71K9mSvdFV9KUzca6YYbnzHQaoPvkgw9VSWmV5\n3+/iGt7apnBinavWE2cPo6qhmy+Kh+2vfG+SSyf+C0lsfLxwDaFt+34Uktgv\n2x9TrQbxYa6ayc4CqazoenQsP9GQTW/I8KULqYe5sO1sYS7V3BY3QDYlx4TC\nPlL0o68HygAv39EBOJPRjVPXRj0mYSU7Zz27EbZl4OC7+lXwd1pWKHlYpYhS\neAVIkGnr0DSScfIUXA+Wxy00Tk1NBdpb0ef9BpIdSwrRuhVrtQyxgsxazN2Z\nNaJAnhz0fL3b9Gs9tBoD50HSPkqb0is+15lSW1dOpfANdPtUmLkB+2T6ni9f\nrN7qOyToGHdpQ4JiGB7fVBLpydrF/4NyZG0OFrwDnpfM355QXjYGhXYyQBUk\niXpNFD/f4AvsWiaODw9TAsrI4/tcqhgPTC70dO3kCJv70m6T4gxDYvLRl0gx\nAlBIUUko36+AEpMXuWOzN0NlVK0BZk45fTlrFfRoAb5rtHFhAaezplIEfuo5\n08tZgNYDfcAvjqDV2zJ7HXcvvkdDLxDzVO8hEkwO7yJZO8ZC545Jqlcp/cOP\nZhKM\r\n=dcFr\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDKAw6/cTJ+z8lwR6z+Nr06nbK0gq01HDzD+fzuh0XmpwIgX/Z0dqTkdOqbBtpdXFcE8E0iet1ynq7JRpYxXdiEemg="}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.6.0_1606428806156_0.866420729544489"},"_hasShrinkwrap":false},"1.7.0-rc1":{"name":"micro-observables","version":"1.7.0-rc1","description":"A simple Observable library that can be used for easy state management in React applications.","main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"license":"MIT","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{},"keywords":["observable","typescript","react","state","hook"],"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.onChange(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"58557ad59b1ddc8e6892d42c8493bc2cf10581bf","_id":"micro-observables@1.7.0-rc1","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-fgMUntNy290iXEe8ar/jTcL4US5vnPKuMH/gQLBskuKk4G462C51/KJW1KpkucXhqmpOvq/uJLsawNh98N57EA==","shasum":"e6f09426fa846516b74b763c8b00ecec416328cb","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.7.0-rc1.tgz","fileCount":32,"unpackedSize":182078,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfw3NjCRA9TVsSAnZWagAA8r4P+wTPUa+PtjFDfHSm1d/S\nBvOYtIOFK2Oh2U3EqV+LdvFDarLrcCSnKUJUgumaN8OR3onnTnHGc8TNvyKa\n2iRNKUYyzZOsPAzK5gSQ2H4wBz8iMf6BSnE7wpFD4zOVz3CMJl2NUFD4AA0M\nbjGxB5s5Fu39pULcCnH9LBGTXmC9wxyDR93DYZxa4lXE2BAbTOwoHGqv6ML0\nR5TjLihsX6LYgofZ/zT3KSSUztK8jrIfQbcbb1MPeDw/gVsv8oeZ0JX2ZLwJ\nuZbj709jFLa2nYeveOtbE2S0EDT6oPD8qf7ePBuSiGnvMfjTQErUYAkWl1nc\nk67QsGIHjzpXlfWWhwZOtOkO7wpix3DaMKGR/njhbSlLz5zbR88MlXX2Q3+M\nqjtkS5UgPORNkp6pDr3CicydXVdiw3sPSxQ6clsg/IPsEtHEDvQhjYNjMCSP\nd9qIx7R71NYR7LQcrunhtPVNn83uOnrlRgOkpocSyc8yeGuJ2w+i+pgDDG9n\nCZ0AE2mUOJcWgPJRTGFkJr5tf9gIz2Am0+EefDG32TeoOuaeCTRzraxjffev\nI1B5SBS/ZQsWFM4ZH5mpCnoygJg8fpJMpdr8Zwz9HyCYyuSkF7MyH59Jp9zs\ns+VIP137bJMaIm1tawZvKnlS1jlEtZCXBAofQMD45g9RwZuIuIXmsTZUf8Bq\n0+nO\r\n=yvkk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIH1zrZi+CT+Uezhr0TRM/8fguCi1lriSYJZXcBZL5eTXAiARZEXUqXSaJfLIj+6/9DCNZyvsQ6shlwcZEvVc7FG5pw=="}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.7.0-rc1_1606644578570_0.6312443522718842"},"_hasShrinkwrap":false},"1.7.0-rc2":{"name":"micro-observables","version":"1.7.0-rc2","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{},"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.onChange(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"d68ca0e82e406a9b63363f5199e5f50bb95b7b4b","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@1.7.0-rc2","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-sVcO/Wo0ZQ872m1ZWUT8tAfP57g9z7tAzgt/xrBJCexhyL3n5bX9a+4VGOxT4qOkwn7J4FhoxOmMdmWRgsFJpg==","shasum":"ff2e3017372fa0f5eebbb52aaca57a55dbe3100b","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.7.0-rc2.tgz","fileCount":32,"unpackedSize":182046,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfw7/ECRA9TVsSAnZWagAAb5QQAIe2CRHKSjVyhDHuP8yq\n0CFRWqUbj26jp0Dl3ah+oY5utjvReYA2e4IEALY0K7jQ3LGpLAClcLbYScDJ\nJROJETBGy6C+GUetqGudY/btvpHsi4tg52afrtWnczxIDvWItktgmkoDxxKa\nxaasU1vJBVAa2VrT/n2ix0fperUGVffXrjNmWsgg8Mk+SSSg2Wxsv3mCK4Ix\ndsvOvTlUCb4oni4Tso82y0dOGdj4QFDwzCGMYXryIE5Lt9TzUOR73RY7vvsd\ngONcSTlai6IiEvyvkWsVtrV7kziWs3ZS6RcTrY2Xy1D8DVMAIeT7wHRbZJB1\n4jqKTuVtlYaIfWHb+EI5m+XQ8BR/nz7A3uHS53T09MJRjlaLGP4v1d6vLTRT\nRbcR4YfGKARxQ1ZexCZ6U7mhOQwbbag9719K1UKYdyhaiXcWy2x7/EntvzWp\np3AAPtGPEXDChjk7pFq5fjhWk1ggsRgPXxgZwzPw5pmAIbPUjZRzmKngtkw+\n959U192JLd7duAUMtFSwZ+nhfw1Rztr2XaeUw4l6d7pDt9pEJGoXh54DKNO1\npiE8vgtO5/SsZzMN7oL0XgaT8Q1xuCVQYd6FQZXomUN+8KLvW7EB+QLM85lw\nESeWWuAJqbkoPw/TVHqI3WhbrkwNApqlXqPAAuMRhAyms9Z5UEVwOO+01RlL\n0xFy\r\n=3DrN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDLPZnDZtStgXL/xKHpjZliNGI5dcokVdJVxfBKB8xCCgIgFqmblgP26Vc3pdf3Fsgcb1R/CWYa+669Se/B8C4ToWc="}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.7.0-rc2_1606664132112_0.7013361355776195"},"_hasShrinkwrap":false},"1.7.0-rc3":{"name":"micro-observables","version":"1.7.0-rc3","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build && tsdx test"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{},"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.onChange(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.onChange(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `onChange()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.onChange((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.onChange(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.onChange(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"a766ba97fd059c2ed9a4832f947a062ac01b6561","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@1.7.0-rc3","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-0bxQ/9QV1/p7OTAY/+SWNooEjnKgc43iVH4ojBl4rLoZ4ZFSJMMIIXrVZHt8hoovHqTidzCfHIoL3h0VyyseEA==","shasum":"7a6ce38d5e3ed06e6913a1532008181ac3e76b5d","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.7.0-rc3.tgz","fileCount":32,"unpackedSize":182315,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfw80mCRA9TVsSAnZWagAAjWUP/3GlnU2M90aWAYnUeUZv\n4MVvfr8/XaOTA6pQ4hMi/BolDWgjxozd2KtqtwrCcEnifGnAiWASPKilVVyI\nodZphIWgghW+N7b/5g0ffncKjkjCKX6rcQwJh/Q0s7jD8FCzTDKn2UEsdfT2\nNdTEstiEBAQXL/F7ZWo+bLfeIhdZESrvnKL96CcsXz6QS5A9fO0Q3AkJrF1r\nG0BWyx30tUa8MDkGE08AGy2FTJNMtKkhJfOEQLdyrIHOWwLSgHY4JMyo6le6\nVqSTRqUxwxwKMSOhCKFYSyegPWUQq3/dU9ZL4ZBqJBuqSQJbu6RiIkkJ6/8v\n610QgpmrA5WQXPUE7+Gxgvgm87YZ91FfM48YBSKMEcBROfVhmhNdCYz1hXAE\n7kW9m6Tqlh5GFth4WzJmy+uSb6EwdWpsEvs2au8stvUWHyTk0EcfBgxQQBHh\nCN40PA5npY65nNvFO4EDUCjhs3SwWdZq7+oCpiXcr3T1VjnhpXvf53OUzZ9w\nkOhpZTrkiZxkzRzDdtvj/tEtTpTTd9Qy3t5GGdeFoZBuk8CnaWASZHOAWlsm\nt/HY7cPTkU+mqxCKhZh7QFC/D9SNrrlw7aE69jc5CfBXS82jA4y4kgZPqgbG\nLw5AJy55I/9dQuzmhf/s4O1K/vSsOmG+qER/W+Jf/5VRhN/ZxNKS2bw14Ifx\nEoWh\r\n=YZsh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICzA0Zw/D2c5lWdWjZsYhSllIBpeVdHwbxuJmgtVwzqRAiBRBn5I0fPa0M8QUP0eBxXqhOf3NscX+TeAmI0sC41m4A=="}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.7.0-rc3_1606667558001_0.005666136039516045"},"_hasShrinkwrap":false},"1.7.0":{"name":"micro-observables","version":"1.7.0","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepare":"tsdx build && tsdx test"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{},"gitHead":"69c68c0910c0a8dac4e3842a010806e51b712404","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@1.7.0","_nodeVersion":"14.15.1","_npmVersion":"6.14.8","dist":{"integrity":"sha512-FubGqb6QaewjOm1tuz/kf8/Hz/RoG9UdihiJlfryLNtrHefQLYNWtLmKOrtli6G4+QCdeyeQmfcTZ3HGN2G04A==","shasum":"7c7709d66bb5391f398c917f30e4ec9109858512","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.7.0.tgz","fileCount":32,"unpackedSize":189697,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf7tCJCRA9TVsSAnZWagAAN4gP/i4k0wrpIENJUDhAeSCG\nbgxN+IEifH7IVEtMEKWfM7f68BL0Z67bs4TRun/rTn3YsSo7DHQ/WO4j612e\nDCmkNxfff2951Y8kFadXm2s0/KTN4fz4/08szIOnEXmu5jerMNF8KniIrsMX\nqloIkXbZY7z7aYyX5fjEG3Hv8cAeLTWtYTBRkjDGAnuKz2I6NZT+riZhIczj\nNeZTPZDobKGm5w+GZVNFXI8rik8TRsgh9bviFZMVHBS8ircScoQxWRFzPBBG\nX36LC9V9jG0BU3dBBN3XrSvQmZM0SNdf5zO3mI2KpBWLR641lZKbAE6jIBSc\nfZHDcSjUe4t7Yk9O1ln/jlddNHCu3ivdz9TWg4Gy5yo5Z/j2lj+axKne2z/I\nM30JkcLiZywtRtk/kGwd/JFzPuC7sWxUej47fRYnB/l75VmD0tZH+mDBGS33\nJC9t1tdg5bFyfGSu7lHAVCKae+H3CEhKTF74FMJJnzy/L1m1xUDWeXLb2FuR\nduHcH0GKwWhp/n9uld/IYH2Tx9UrSwsXCEuUIiz7JOovLfqY9nyip7LNXZru\n8fwwaJjvJ0yhWMxF/T3/9U45sfdFnFgkmWANxVaCSHnUfJorrXO1sT5bIqYM\nkDHHz07uO9Jau+jdQymQ41X2PD4aVYS9/iKUvVFQX4wOnSsq0Xzg6CPOwjoc\nXV4K\r\n=HRut\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCem/zOnPVSZ0E9PJpaB5EWvhIkkj9Df4yHlcSdFaaN6gIgUK9K1qZVn0DUPLA0YUWF9qI1A2omI3E9AFuRzH9ZPyE="}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.7.0_1609486472822_0.5184709575815589"},"_hasShrinkwrap":false},"1.7.1-rc1":{"name":"micro-observables","version":"1.7.1-rc1","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepublishOnly":"tsdx build && tsdx test"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/hoist-non-react-statics":"^3.3.1","@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{"hoist-non-react-statics":"^3.3.2"},"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.subscribe(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.subscribe(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `subscribe()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.subscribe((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.subscribe(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.subscribe(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"908a2d4dce9811e5e8a3efc0b891c066b5aabfec","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@1.7.1-rc1","_nodeVersion":"16.2.0","_npmVersion":"7.13.0","dist":{"integrity":"sha512-H5ra4nEHcZJSaAgrLhr3/ki7x7ujF89oKrbBQS4LoniM4lbzM2Fph2jnJPfiVlZfr9n01PT4bAvuuaOJBCHaHQ==","shasum":"341fcd0cd6bb9fd4398d4b283099e121b9533c7f","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.7.1-rc1.tgz","fileCount":32,"unpackedSize":191948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgpuBwCRA9TVsSAnZWagAAK2oP/1sU65ag3tz0ydL3NKDh\nWh2rYU7SZj8ISBYLlCyc4octZuDYL5G06pQ3crDtRDac8FVSguB6IE3eovZ3\nYTmVF5TAW+ev5h196lALNqq+cAMlZ6C9hn/hq4100nM6eDsn849DlHqV5eNE\ntiDvNNWUMd4oBbUimJ91KyJ3kd5/qsIPddh+tj33gdaioJgXGdutx9lNmWOE\ncNlQ+F5Ab/WAqtW+DR4TBQc9RGApSOL/qjeMHf5Dk+3lpdftg6RF2VWZ3dtd\nW+LCSHVcJq5kzO2FuFEoIdYej6s2THpmNmuboQDC3txqbSV+goBhrORteD98\nAbQDJKnNRSdBhxRWSEkI5E712s71wpOFK72MoWNi8NOFi7D0s29wRAV1wx5D\nJMOuzzbpigIcz7CEO4t789PKMb9YcE6ILCSSiRPLfVc+RIZ/aja4CoU/6oAv\n12/mxhxYXpuoz3jgPMt5Kzlk3t85ZxcHUAbqj8kpRi/uIyVnEpl6bTvB9vyy\njjZumDrYFFJAIDWcWrokywUMr2khqQ3MVqMW1HnMyXqIawFtxmK5m47o5sRX\ne9MSYyFmrzmJVY43kYE/NZ+euDlPvXxcsSHY7CstN363I4SKt6l+q7fb8qn4\niuf9i2EElt4rPs+dGr0VEffwKZqFM2NUwpUbi8jFHF1LOzWLu3RV3B7b1kHP\nPxGu\r\n=VEl8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCJeNY8LkxO3PEipY+K6KZzFi/lfdqEuioeM8RJeL7s2QIhAKsO7stbKXfXh8vUdqTOqSjU8uwvv8I88/5WqP82THGO"}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.7.1-rc1_1621549167907_0.38996852153083217"},"_hasShrinkwrap":false},"1.7.1-rc2":{"name":"micro-observables","version":"1.7.1-rc2","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepublishOnly":"tsdx build && tsdx test"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":"^16.8.0"},"devDependencies":{"@types/hoist-non-react-statics":"^3.3.1","@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{"hoist-non-react-statics":"^3.3.2"},"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.subscribe(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.subscribe(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `subscribe()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.subscribe((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.subscribe(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.subscribe(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"23cf078093274a1ae4495b0f0f1594e20f248b56","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@1.7.1-rc2","_nodeVersion":"14.15.5","_npmVersion":"6.14.11","dist":{"integrity":"sha512-y3wEe1JOLfbXWIU96D6RcTaMJbufSh8Bzk3/cxpdEbnkEAqc6jfjF/4bst9u8YBpsMOxSpcsHdno7TxEGIQn6w==","shasum":"2dbb1d8ed740b402fad0de48bf6ecac847b7b9ed","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.7.1-rc2.tgz","fileCount":32,"unpackedSize":192328,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIADrqnUV2vv8zAiuvO6kXKJgMjN379qD52W5j4e1TLMeAiEAh/u+3q3JfkF0bnQgP7D+GhGS6d3UtWMSjzwiIP0B7i8="}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.7.1-rc2_1633118869684_0.7084308884075252"},"_hasShrinkwrap":false},"2.0.0-alpha1":{"name":"micro-observables","version":"2.0.0-alpha1","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"main":"dist/index.js","typings":"dist/index.d.ts","scripts":{"watch":"tsup --watch","build":"tsup","test":"jest","prepublishOnly":"npm run build && npm run test"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","prettier":{"printWidth":120,"trailingComma":"es5","arrowParens":"always"},"peerDependencies":{"react":"^16.8.0","redux":"*"},"peerDependenciesMeta":{"react":{"optional":true},"redux":{"optional":true}},"devDependencies":{"@types/hoist-non-react-statics":"^3.3.1","@types/jest":"^27.0.3","@types/react":"^17.0.37","jest":"^27.4.3","prettier":"^2.5.1","react":"^17.0.2","redux":"^4.1.2","ts-jest":"^27.1.0","tsup":"^5.9.0","typescript":"^4.0.3"},"dependencies":{"hoist-non-react-statics":"^3.3.2","jotai":"^1.4.6"},"readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.subscribe(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.subscribe(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `subscribe()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.subscribe((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.subscribe(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.subscribe(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"4e7287f7725b1cafee77e80938f0128441e7e387","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@2.0.0-alpha1","_nodeVersion":"17.0.1","_npmVersion":"8.1.0","dist":{"integrity":"sha512-2c7xlqNpypY3iI3xkBmao/riW/ENlyKuNfozd/rByCPKsGIQRzPqTuLDVv7UkYu0HLrEBWwKvfwiqNI8aH3Nhg==","shasum":"fc73d59abcba2fd48f7f9329e24f63653522cf79","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-2.0.0-alpha1.tgz","fileCount":18,"unpackedSize":62602,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhrUz2CRA9TVsSAnZWagAA0gIQAIL7hiDoYQd9Q8+ScjWE\ntX9/dFniGh/UuhBasX9iOxE8woEqYSxXNi82moxG8IbQwJchwvMoQqcsmhdc\nilx0XDucAFMYhESDIM+PP92BDJQpZxaCuQUWTmUZMnUi+lC/tmaCiTuZj/5r\n7lbAmuizAAuSjcCSz/nxrGlmURFiHvS72PbyFEDShd6JnkS5Rcm5yn96Km80\nd3xh98gq4iVxe/JbLjAE+o1EoWTEcj2/gS2h9n7200ws/7tX7E2xYU3g4Ghw\nnCvim/9GOM0BfzCVI4rDAhRvzVSAH9HVfGArtZoX5DPwWQjR3kpwP1d1C1l+\nkUHev3ojrQHEP40dSpYozOymyLSAx/Tk1ymLoGuDEVpGhYOs3IPWSao60YnI\nbfEsJ9lPyHQoytDFI0XmHi5MrBmWAaYaTQIj3V9+Kie+0KvF7BLa4Sik+jEj\nx8sJYrVYVqC9tEj4Vbv2Xu3lploAXfTxO4+eS7KG1CgUNwDXKc+M3mkU6s4w\nD8EyH2/onyf9soqstNFMLeIrPZE4nWWzWH2jhER+oVPXLni9SsydKK5ZrfyM\nGqGI96Fa6CDMprb6sXJCu8CSXwQqODviiXjMW8f6AsWbY+WVjCN0dfBoILDi\n4kjAqiOXQLDhjmrshDaOyyuHBLL9uNRxtCNAYFheb+pYlzGJLnLBiXzWNBpb\ngtme\r\n=xEka\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC2HPtkZit7mC7H8VjbmhRkS91HtuEJz+lsgQu9YK9OtwIgSXsLcLilAU03VUb46LgiviGX3m+xyPE8nsePx9UMHr4="}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_2.0.0-alpha1_1638747382292_0.22534237136131274"},"_hasShrinkwrap":false},"2.0.0-alpha2":{"name":"micro-observables","version":"2.0.0-alpha2","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"scripts":{"watch":"tsup --watch","build":"tsup","test":"jest","prepublishOnly":"if [[ ! $PWD =~ dist$ ]]; then echo 'Use `npm run dist` instead' && exit 1; fi","dist":"npm run build && npm run test && cp package.json README.md dist && npm publish dist"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","prettier":{"printWidth":120,"trailingComma":"es5","arrowParens":"always"},"peerDependencies":{"react":"^16.8.0","react-query":"*","redux":"*"},"peerDependenciesMeta":{"react":{"optional":true},"react-query":{"optional":true},"redux":{"optional":true}},"devDependencies":{"@types/hoist-non-react-statics":"^3.3.1","@types/jest":"^27.0.3","@types/react":"^17.0.37","jest":"^27.4.3","prettier":"^2.5.1","react":"^17.0.2","react-query":"^3.34.0","redux":"^4.1.2","ts-jest":"^27.1.0","tsup":"^5.9.0","typescript":"^4.0.3"},"dependencies":{"hoist-non-react-statics":"^3.3.2"},"types":"./index.d.ts","readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.subscribe(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.subscribe(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `subscribe()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.subscribe((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.subscribe(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.subscribe(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"4b8da1c59e40d85138e8c94739fe8f12c8c5c66f","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@2.0.0-alpha2","_nodeVersion":"17.0.1","_npmVersion":"8.1.0","dist":{"integrity":"sha512-epJVRdJwqBbD3760Ibkh20QAINkoumVwkixf3q42Mm93ieZJsNbzGxVSx5fkWEaTlmkjp5YlLbSJRmf2WCq67A==","shasum":"165722ce1aa03a5fbc9bafa8d0cdd55ac18f7d82","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-2.0.0-alpha2.tgz","fileCount":16,"unpackedSize":87207,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhrp6RCRA9TVsSAnZWagAAkrcP+gInusmODEYf4SIypE4N\nGJ15eZY/hpz6nMpDpcpHjcp1WdWSurpNGfZTOffXxB0SSu3AXyInE3xp7aUp\nbLT42a7vNlS9NQI+R4hrNoCv3tma6OR3uzDQTH9i4dlQ6zfLkthPQ+Pj8ngh\nSKelJSigcR7mOzy5llTMxL9RrbnUDEqzud6bJ865LUARzG+o2lr98LYRaewq\nSx2/STTA6nrxjmlKC4APhIJ617FLfP3Bj0JWa95j38V8KJa5t6XKl8/d6hab\nOictv9IVe6e2jTi+ST/L4eyIpaiHNCzp1rUGszh43KN3gCGX9XTaATL3cAcq\nTIr6/ysQAE1C23gY65ijiq8hDkfdby4JXaI/1ui+5eaW/L47cDIPyPMSwHau\n2hytaR6E6bHtxsFjtO5jdVjibvGwc+9+WcZrJTCPLrLGgeMWogDP1tKaP0gH\nWfH6Jv1kbrI4qP3fI44hUaFOyYN5wZZIc3GL2fitsJ/QKIENCn0kzoP2Jqae\nFfA3or0ql1qdLA7spuPggGd3/Vplh3UYo8K6idcOdP0jwz4sP5GB3B543fAn\nV6i4sy2JI8ysCtCmHyPOsk+OksTbHRcR6IVwdbk8gXyqTlaQ/gAcQubtVBex\nkVL9SfcVxxXTWC9gs7631NNwZ5NYwent78vsx35ZxNIyqEEF87NgyRIsiC1r\n5wgz\r\n=htua\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCz+iPjORFqYe77cYA8Dd8dJpLgB9zhmZ6139pBDfJ4LAIhAItX5vHCqDFUudjU8irV5Rvf6sA6ZGr0rb/xKUkuvVuz"}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_2.0.0-alpha2_1638833808728_0.5672149333786514"},"_hasShrinkwrap":false},"2.0.0-alpha3":{"name":"micro-observables","version":"2.0.0-alpha3","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"scripts":{"build":"rimraf dist && tsc","test":"jest","prepublishOnly":"if [[ ! $PWD =~ dist$ ]]; then echo 'Use `npm run dist` instead' && exit 1; fi","dist":"npm run build && npm run test && cp package.json README.md dist && cd dist && npm publish"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","prettier":{"printWidth":120,"trailingComma":"es5","arrowParens":"always"},"peerDependencies":{"react":"^16.8.0"},"peerDependenciesMeta":{"react":{"optional":true}},"devDependencies":{"@types/hoist-non-react-statics":"^3.3.1","@types/jest":"^27.0.3","@types/react":"^17.0.37","@types/react-dom":"^17.0.11","@types/react-native":"^0.66.8","jest":"^27.4.3","prettier":"^2.5.1","react":"^17.0.2","react-query":"^3.34.0","redux":"^4.1.2","rimraf":"^3.0.2","ts-jest":"^27.1.0","typescript":"^4.0.3"},"dependencies":{"hoist-non-react-statics":"^3.3.2"},"types":"./index.d.ts","readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.subscribe(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.subscribe(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `subscribe()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.subscribe((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.subscribe(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.subscribe(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"8a5237bd9ae7842ce34fe2112e0578dae360199f","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@2.0.0-alpha3","_nodeVersion":"17.0.1","_npmVersion":"8.1.0","dist":{"integrity":"sha512-FWftZlr1Zz/jAuZbYUn1JUzKHaP6GmjNABaTzJv6vup41RBnioARW08Cjit3vOS8pD3GYprEIgECn0GbF79DVA==","shasum":"e81e5607b5250dfc09b781025656bfff428da813","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-2.0.0-alpha3.tgz","fileCount":35,"unpackedSize":59324,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhsn+QCRA9TVsSAnZWagAAx4UP/0H+PCVb1aHBApFLjZon\nj95kwVJGWHW/FZ/PbYwXqtjtRL4zuQu88SDkpa0Z6JNLrH7TeeIVEApEVba+\nO4R+OkWoQY2vipAB4PxkxGZbboD3BiPFG91ioE+PupNO2wkXu6U0E+9RnaCv\nnd/tUl/lfGEvUX/LmgZYBrRUig6zPSjp3TgTwEpmJtHPaHAYEmD672FprLzq\nRI+uQ/LQw6n4Wvoqk2K/qMtqsGH4uD25LacLnYFwjrM6eIRlGM1hF7e/RjoU\ng0c9QnqUg7vurYiildunHbazZva69wU7PwURUubWebYG0Sh6BfUxj2Sv7JmE\nO0ebUq+YatenWzSEOqkOjn/lQR7saTABwRDqlLfaRjkDsN9vEySojYDM+Ubw\nbblzcz5IxFIwWBDLi1BT1+K561bHBvHCTpkT6UmaaBViA7eMwzRPQW+kUuJU\nLJIrtbXK9onxzMTpti8nU1TwLB7X4TbvBXZSYfmZqE3wzlRhKW7yp0wC3/3Z\nG7voXm8TJYpnszWRUgRKDCbCU5Qa8r81h7Kf+XphjfOA5aki5otiLMKQxA7r\ngzVNJbk1/+ZRBaAoyHnUVT5+jswhcC11yPDqcH0mw1IebAsHPhnD+HxEPEmq\njeMdJa8A2sUNoJhuMod7la7jQaPujcqZSotygQ/EauIUbuk8GbSzOF3QgnKC\njCMA\r\n=Zzaw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDoIKh4QATYMcxJ5YTuIaj+G6hkNIBlZsoQF5xMeMQ2vAIhANH7keYdWxDhJPLZUgVzafBqDcoz4age1tJ6xvQLidxJ"}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_2.0.0-alpha3_1639088016534_0.14756222172937994"},"_hasShrinkwrap":false},"2.0.0-alpha4":{"name":"micro-observables","version":"2.0.0-alpha4","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"scripts":{"build":"rimraf dist && tsc","test":"jest","prepublishOnly":"if [[ ! $PWD =~ dist$ ]]; then echo 'Use `npm run dist` instead' && exit 1; fi","dist":"npm run build && npm run test && cp package.json README.md dist && cd dist && npm publish"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","prettier":{"printWidth":120,"trailingComma":"es5","arrowParens":"always"},"peerDependencies":{"react":"^16.8.0"},"peerDependenciesMeta":{"react":{"optional":true}},"devDependencies":{"@types/hoist-non-react-statics":"^3.3.1","@types/jest":"^27.0.3","@types/react":"^17.0.37","@types/react-dom":"^17.0.11","@types/react-native":"^0.66.8","jest":"^27.4.3","prettier":"^2.5.1","react":"^17.0.2","react-query":"^3.34.0","redux":"^4.1.2","rimraf":"^3.0.2","ts-jest":"^27.1.0","typescript":"^4.0.3"},"dependencies":{"hoist-non-react-statics":"^3.3.2"},"types":"./index.d.ts","readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.subscribe(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.subscribe(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `subscribe()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.subscribe((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.subscribe(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.subscribe(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"1547479bf74f48fdbd76bbae5e6b86aec1566e5e","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@2.0.0-alpha4","_nodeVersion":"17.0.1","_npmVersion":"8.1.0","dist":{"integrity":"sha512-1aNRl1F10qKrXFA6y9ULsibKaPtTPbnO08rXLemxCPiycxumu0HVU1tb8cOYtB+pda2GYDwa+/M7vKD8gfLs4g==","shasum":"300b7ede8853dc37fdb82ef4cb3e7eb15792f52f","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-2.0.0-alpha4.tgz","fileCount":35,"unpackedSize":59059,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhsozpCRA9TVsSAnZWagAA6EQP/A7cTamCOiseFwnW9Y5l\nxYwuCrVET4h5T6m6UCQLL/dobNB6d+rkh51hdUB91N2VlJ0V2qG5c8EkgHQr\nuzM/PL/urX2v4OD2a1Br7Xsy6xreLr6u9+Omxdxd9fgsChqjVViV4Djlpuxs\nODI7HItsB67zwO5g8KTPlT9T408EF+Edi5EXlorY5+hWF/tfDZn6acq/nGBF\n5ZHQjHKPHWKiLv0DGnc3DTLuCxtcaGv8AJ2zebLWqgOMqSrFEznefQy+Qlkr\neq6bYxMsAPS86jDk2/rK+bbAtONLMhqgt6XoZnClgbloFkKMtFJcXMHvzI4W\nXruE1Rh/20Omzo6g3JZ+5inWpai8WQuGmvF8Qmlc6nRwYqUeXhfX30e3mWdp\nqgwq4n0XO/Ca6VXBW/2CO3iewzZWgU72ax0tz1Ri0Y/EINc+jaYjA/48pE1m\n+MzxvWYzRcmAp9jegbOISbYaSu+BQdOjCXf08w6yfGXIhOaLz+MSX6z3CoEG\nPrWOfMS8r4cTh36VZzBVUOU/iC6cIDxvwu1whfq8VaoAzPiQOWa40kKZ0Mqp\nMfMTklFNimUMXJsclQkceognRXQfswt1lShsIcnVE9ZlwxN7Zpph5qTZBF92\nt86SpnK/dM56PaQoVsXzm2+JluJc6gGXhNMkBSViPF0+OgqbPRsay1lo1Ei6\nj52G\r\n=onbo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC8DwzNO6Jc+mI0/Yg9CZtvy6E3NqOSAaH+tdJAz3lQ9AiBkPPTXikSIqwvnZz5OR0XAd79tCVI8eZ2Gs7imLNCAoA=="}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_2.0.0-alpha4_1639091433451_0.01908294457667936"},"_hasShrinkwrap":false},"1.7.1":{"name":"micro-observables","version":"1.7.1","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepublishOnly":"tsdx build && tsdx test"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":">=16.8.0"},"devDependencies":{"@types/hoist-non-react-statics":"^3.3.1","@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{"hoist-non-react-statics":"^3.3.2"},"gitHead":"13658bfa66e51c121d94dd988921782c23675bcf","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@1.7.1","_nodeVersion":"17.3.0","_npmVersion":"8.3.0","dist":{"integrity":"sha512-Q15FYI1RMCtQT/2ZvC7aJgCHWKq8TYAfLTwhxsMm1x5JQP0O4E3r7Lx7dsB2GFUyr7hK46tqJZfuWZTpVI3KfQ==","shasum":"af37f23fa6dd32b2728151c79040f6b1e0b44989","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.7.1.tgz","fileCount":32,"unpackedSize":192325,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiLIjhACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrUrQ/+I0BojcrkczKEkxqoyZ5HPdtnOFNbLpEYlIGcyitSt8aydEck\r\nTASRJ2vWByMkD0/6WUe0Ej1lDMuyzcQxGBOvPMLU/b0CmVI93/qyYP9zkJYz\r\nZB5uqN5k/RELcSF/zOfJe45VggXY1l4lNfrVY25ZjUgWWNMsIPqJfaZZNqaS\r\ngQN0MEgxTEHZ2u77Avbv4l9VcoxRoYeQGAIFgPZy9sPzy7mf37OSl2Yzsu/l\r\nM2+uIaREO6P2WyoBywd00YFRkEfxCB7/vYR4MWHMV99QCO9yL9RCkOmoCQWS\r\nMLciw5B86nTl30RCBS66nQXbb7awC2VymCbYxw3oZ2n5ekIIPO1W783/Qcp8\r\nc0ay1Ct/Oq5SPUd3bE5+W7s8FACf/FE0Ypgo1F3mB2+H7kFcuogmoFZQYomO\r\nJraFS93n1Q1Y4cZPt8RiWMHJD2Pwr9LaJG1pD1UCu/gHshb3Gb25V/CgRITB\r\nMjkx1MfkGX2rHNMZeTgWWAG52s/RbKYFWgxwtsZqvjICKsMMomQaBzYLFDTc\r\nTILw/u0NVaIgpWyosGm6+VQwHo+3iLJCfYEMN342wjTgulgJ22P3a7VeIOma\r\n9X0AAozCqhvBq0aFjAPCJOuZj+rqOhnAsd1P2AIx7eQB89kr0WpolXOcKaph\r\n6wSvqTBUMjcOnWSumm25JzjMKx5R7wyHqd4=\r\n=cZKo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGdOfLUW0RyYkQvixP3q+irFct8vaWM1kQUObYY4A1AZAiBQ8LfXmd3pPszuzmSjIDXYvq2emSp3Zh8+qxcJ1+THpg=="}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"},{"name":"alois-beto","email":"aguichard@betomorrow.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.7.1_1647085792883_0.9978854548494236"},"_hasShrinkwrap":false},"2.0.0-alpha5":{"name":"micro-observables","version":"2.0.0-alpha5","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"scripts":{"build":"rimraf dist && tsc","test":"jest","prepublishOnly":"if [[ ! $PWD =~ dist$ ]]; then echo 'Use `npm run dist` instead' && exit 1; fi","dist":"npm run build && npm run test && cp package.json README.md dist && cd dist && npm publish"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","prettier":{"printWidth":120,"trailingComma":"es5","arrowParens":"always"},"peerDependencies":{"react":">=16.8.0"},"peerDependenciesMeta":{"react":{"optional":true}},"devDependencies":{"@types/hoist-non-react-statics":"^3.3.1","@types/jest":"^27.0.3","@types/react":"^17.0.37","@types/react-dom":"^17.0.11","@types/react-native":"^0.66.8","jest":"^27.4.3","prettier":"^2.5.1","react":"^17.0.2","react-query":"^3.34.0","redux":"^4.1.2","rimraf":"^3.0.2","ts-jest":"^27.1.0","typescript":"^4.0.3"},"dependencies":{"hoist-non-react-statics":"^3.3.2"},"types":"./index.d.ts","readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.subscribe(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.subscribe(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `subscribe()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.subscribe((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.subscribe(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.subscribe(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"85236a8391d993216d6f56a0970578301be2e112","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@2.0.0-alpha5","_nodeVersion":"17.3.0","_npmVersion":"8.3.0","dist":{"integrity":"sha512-5t1QwH8+RzFSj++nanaa0tiZqCoMFNNslQ/fTvvF1x0uLc9Bxsl2XqSaJGrSUwPhWa1H7THCykOT3/pWOJhGLw==","shasum":"1fd88d3f24a24a38e85683dad5db7714f9a9bcb7","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-2.0.0-alpha5.tgz","fileCount":41,"unpackedSize":77745,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiLInPACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrXYw//UIWaES4wAyCtidUpS3nNPFxkrxkTzSY22DLrsjoIEFxNLJy8\r\ne3AfbEFPBtkUWdiTTADaXOsn30WQJqQIaV6gfBiDosTb5x4fvoCcKC9IFVfz\r\nnBK9MTymIIZ6kYq5caxLj8BDMnMjO9CilDfkwdfOhOmCTKniUTbW5DWZmXtc\r\nbo5+lenAicaO2qwgN8znCXcuNISmyoVPVeyphiRrhmia673Ifkmav8n0rX0S\r\n7jzjPjANxkIaxe9vowU35g9exA7CucGXzNfsHZo/gQs6KWPtomkPFBwE8iRK\r\npY7d55oSV/1t/lLJ7cAf5M9L9RBLJx+RJdmRxxFcn2x6LKotd+O8/DV+9Rx1\r\nAk/nEIHNiF+YCdPX0/TBBRdzewAYX3I8qrP9bBwhZkXUC/ok11ZHMSuetfwK\r\nT56xCtIo054QgJciw+8qawSSCPeGONJkkK4ohklKdwikgRWH1zT8OYm4Ei10\r\naW3XlO6CTGquXU+xk+RhJ4SCyr3HUd1vtXTC70NM7gKPKmz39LpM+SThTUMk\r\npKMoF3k+hhNh8Wgiw/FhaPJmcWEPBw/Im38WW8MO1uxP2GOEwOa1aeGORBaI\r\n6OYruFC4SfGPnDEfs4KrmEU8hbxyd3WE9QjbQQoGDMegWLlV/i9eoe+jCLrC\r\nYbMtQWTztResXXd3KRJMBh1t9CK0OgybE+k=\r\n=3cwB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICtBKq/uVHhoeC7X854ioEF/Os9u1iKjeOZ1uiKF/tinAiALOsBjog/6ndE1GvqVvcCMoQV4G+HEJ4r/vfzlkoyHwA=="}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"},{"name":"alois-beto","email":"aguichard@betomorrow.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_2.0.0-alpha5_1647086031664_0.25772642972406556"},"_hasShrinkwrap":false},"2.0.0-alpha6":{"name":"micro-observables","version":"2.0.0-alpha6","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"scripts":{"build":"rimraf dist && tsc","test":"jest","prepublishOnly":"if [[ ! $PWD =~ dist$ ]]; then echo 'Use `npm run dist` instead' && exit 1; fi","dist":"npm run build && npm run test && cp package.json README.md dist && cd dist && npm publish"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","prettier":{"printWidth":120,"trailingComma":"es5","arrowParens":"always"},"peerDependencies":{"react":">=16.8.0"},"peerDependenciesMeta":{"react":{"optional":true}},"devDependencies":{"@types/hoist-non-react-statics":"^3.3.1","@types/jest":"^27.0.3","@types/react":"^17.0.37","@types/react-dom":"^17.0.11","@types/react-native":"^0.66.8","jest":"^27.4.3","prettier":"^2.5.1","react":"^17.0.2","react-query":"^3.34.0","redux":"^4.1.2","rimraf":"^3.0.2","ts-jest":"^27.1.0","typescript":"^4.0.3"},"dependencies":{"hoist-non-react-statics":"^3.3.2"},"types":"./index.d.ts","readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.subscribe(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.subscribe(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `subscribe()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.subscribe((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.subscribe(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.subscribe(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"85236a8391d993216d6f56a0970578301be2e112","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@2.0.0-alpha6","_nodeVersion":"17.3.0","_npmVersion":"8.3.0","dist":{"integrity":"sha512-CGU3fYIsVXtwlDlOY74QtUWZiorjGqGr/obat0qA/JB02o7TGHVERXJ4g6wHoBip6KZxCb4u/FgniKcv7RfCzw==","shasum":"932ff669857125d87f42096b279feff89e83d818","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-2.0.0-alpha6.tgz","fileCount":41,"unpackedSize":77676,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiLaLnACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo7DA/+Kyo17rE+rCHjE9eqBB952XnA59JHRVOysgjtOI57ZdtZ0fmI\r\nNvZALumkJwVTXTkLAYRBWvBk8l1Loyj9MVmA1vWjX+vXyfejaxPwAYtvZrQ7\r\nImx8Lzn+gzeO9ieA4APQi+X7F0aCk1JEzYH5hx5xIrNdrD/wCUM8hEG2xu9H\r\nNVyBQIxomDvP6ldC5yL95elH/804MnI8mViMdcyaLbqNzfjtal3fZh1P0zKu\r\nug9fIz9+A0LZjNi7rrgWpzct50QZfKH99QeXlznXqNLkKXYMe8FnwOh9zYdH\r\nsNhotyb+4cq4crJnC+WkD4GwdIQdoghvVPnE0bMcFXCNlbE6ZL5F15m/mbxV\r\no5TE4Kkn73bmYNsX3wvRDzbzgsWuxn/jLGYRETRpbl0OFxJdi5CUXSPMy3Of\r\nDSyUTMqAq/pebdxiiQRM4GqxKuy/GagULDmPp9FR2dbm9Tzk2HpZNAUDMAVb\r\nnmbVKox411vdLu6LH/od0DYSAmAuGW7SQvk4zrPzAwC/TaOK1micAv0DC4ym\r\nO4/btztJdIL4XV0ksdt9xBd/s0mlgFaQJ13GfKeIXtki3xXK03Q6JJ6LCkBk\r\n4lCnIYPU+ZuXuuyJkkWfLOAtOvBcKqdEHOQzp6mspUjCIgjPngW0o+pxF6YA\r\nE93fxscpvcDyy1atWKrDoFA6xPYL/oFqAqM=\r\n=dUqx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICKF6z8T38nLkmBifdnZP+6p+zUbxn0h2mJFRZZzzIMoAiBz3XtUk5t+MFm67Xcrn86j9ovYCX4hLmkPwH/8fFlCpA=="}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"},{"name":"alois-beto","email":"aguichard@betomorrow.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_2.0.0-alpha6_1647157990986_0.2425773344561004"},"_hasShrinkwrap":false},"2.0.0-alpha7":{"name":"micro-observables","version":"2.0.0-alpha7","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"scripts":{"build":"rimraf dist && tsc","test":"jest","prepublishOnly":"if [[ ! $PWD =~ dist$ ]]; then echo 'Use `npm run dist` instead' && exit 1; fi","dist":"npm run build && npm run test && cp package.json README.md dist && cd dist && npm publish"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","prettier":{"printWidth":120,"trailingComma":"es5","arrowParens":"always"},"peerDependencies":{"react":">=16.8.0"},"peerDependenciesMeta":{"react":{"optional":true}},"devDependencies":{"@types/hoist-non-react-statics":"^3.3.1","@types/jest":"^27.0.3","@types/react":"^17.0.37","@types/react-dom":"^17.0.11","@types/react-native":"^0.66.8","jest":"^27.4.3","prettier":"^2.5.1","react":"^17.0.2","react-query":"^3.34.0","redux":"^4.1.2","rimraf":"^3.0.2","ts-jest":"^27.1.0","typescript":"^4.0.3"},"dependencies":{"hoist-non-react-statics":"^3.3.2"},"types":"./index.d.ts","readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.subscribe(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.subscribe(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `subscribe()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.subscribe((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.subscribe(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.subscribe(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"29b326380ce7ce13c7f09e71dfa93875196049f4","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@2.0.0-alpha7","_nodeVersion":"17.3.0","_npmVersion":"8.3.0","dist":{"integrity":"sha512-EOtj31KDw7VTvja3X6ojFYab9lAAgAfzOdNGZBgTAjIVo0q3aALAi8SsfVsNhrStfdEQaBCf0D+Gks4/KRCeXQ==","shasum":"be2cf10a4693948576ab85b7051f09f9ab2fef29","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-2.0.0-alpha7.tgz","fileCount":28,"unpackedSize":56627,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiLaTxACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmq+OQ//QDSYswfKWg4cyYxIf+1+oPjz69BZQVmskA12pRDTc3W/Kf3s\r\n3ZyJzTSAk3h43ePxcxn4CyT5IL2p2gAHr0HfkRx4Qe1XHj7ZqMBEi5zwvDx/\r\nnwvV3QrgTZBAKuzlBAA4FuySCZjOOKQZJMUq5BmB4S7O1Ya5D8QSRUNv0sUg\r\n1e61gMzid6AuwzNBdr1G4FY5Cx+oN8dPg7Zj2LbcSwSAzCdutZCernlAf4w2\r\ntsgPuJAXR3a9DuLyaTUjTsjL4T5U1+cCwmsSR6PmLIBQyEBWuxD1KN75eiHZ\r\n8AvCL+5Q6cbNzrAKjUZkm66xjMNvf2t4BxBkDK0CDYP5S+MxBOAjkc1srzJs\r\n5AdoyzJDuxop5lDP531sXNCc7RsP/CBvrOlur3mZZYNkNQr8HD/pDj21g/wc\r\nzO77xmT3apZaUG+y62n4YWPZ3tFbPDR4s2n2IfzR10AenFIzy/aOE3JUFVIY\r\njn+q1jJ6D536DkOOz7C2SpUseh3PBdhJ+MbQkZKXwVHyp9YXcspiteTT+TnL\r\n4GM2Oj5WLmhh7qBlhFkF5k+A9vfQ+U932czy4wvdZY15rF99TZW+pcxRCKt4\r\nCmIlc7Mi8YaRTA9yUIgDYW3KbC4NliUTHVo0aGS0E6N4K3hfw5X9uBT6h2rA\r\nnQJA8j99JXXYHDKrOo+Eku8KoXGARINQRCY=\r\n=Dxp9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAWRkyTyysra8mmpZC/9bJJoGwyEJB8e9XxmByPcoj+dAiEA10jTRJQzPmy3gdhoAjw+sQvnpmkgVQbapPQ3osfjFO4="}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"},{"name":"alois-beto","email":"aguichard@betomorrow.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_2.0.0-alpha7_1647158513477_0.5068694512884293"},"_hasShrinkwrap":false},"2.0.0-alpha8":{"name":"micro-observables","version":"2.0.0-alpha8","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"scripts":{"build":"rimraf dist && tsc","test":"jest","prepublishOnly":"if [[ ! $PWD =~ dist$ ]]; then echo 'Use `npm run dist` instead' && exit 1; fi","dist":"npm run build && npm run test && cp package.json README.md dist && cd dist && npm publish"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","prettier":{"printWidth":120,"trailingComma":"es5","arrowParens":"always"},"peerDependencies":{"react":">=16.8.0"},"peerDependenciesMeta":{"react":{"optional":true}},"devDependencies":{"@types/hoist-non-react-statics":"^3.3.1","@types/jest":"^27.0.3","@types/react":"^17.0.37","@types/react-dom":"^17.0.11","@types/react-native":"^0.66.8","jest":"^27.4.3","prettier":"^2.5.1","react":"^17.0.2","react-query":"^3.34.0","redux":"^4.1.2","rimraf":"^3.0.2","ts-jest":"^27.1.0","typescript":"^4.0.3"},"dependencies":{"hoist-non-react-statics":"^3.3.2"},"types":"./index.d.ts","readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.subscribe(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.subscribe(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `subscribe()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.subscribe((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.subscribe(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.subscribe(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","gitHead":"0a3674b2beb1660dc08ac148f4a8865e33dfe20e","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@2.0.0-alpha8","_nodeVersion":"17.3.0","_npmVersion":"8.3.0","dist":{"integrity":"sha512-HUXcXwtrzVWxBh10q7a5oBOmGL/tRRpXZEpuQXKW6wWhj6qWumJKV6szLcwgm36munfZhT+sePb5UoQ6znw/kg==","shasum":"37d92ef38b4df09e3f4dc57fab95d690615b20d4","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-2.0.0-alpha8.tgz","fileCount":28,"unpackedSize":56719,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiLnNRACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmqgwg//SWOTCtbmSGASXGaNWMc3z9kHyYmGKoZJYzLTSGF0Xha6aK35\r\nGsnind5V5CMI88czqV9a/ZI62cH8b2og9Yek+y5OHLf71WBd1InWBMRwvwYL\r\nqikzlHM+HixLr+4vYzs91SUj9JogXSy344zendzvtZkCtAqyzdtNb2UwT9J2\r\n8ey+7mUpA9dWJ2fyAcVKCTLec2eT1uaNsaWk7ihkW4i0N/6fv0GE1sIW0xcl\r\nG6pzVDPgeSfrRJz/jwnu+5rS110okuHwPXKRp3x3K+RwMXS1AVThVmd1IvXl\r\nYLSgpfEaQzcoufmouJvHqW+TjoAI+vX1zVLMIgjEM7huqGFZGWtTKQT0bTIY\r\nvTI/Qn9Z1/FAOV31elLuOmX9dociBvXwJc91QFH3PgmptFuNmv/mIHD+VDds\r\nY1Bk91qasNFQnRQKn8KgraQWUYCKVLsqZWamG5tidOi4rqT3h/RzT72KTbfr\r\nUT4KZYMn2KD2zvBRl8599roQwRnzGHrQA23OXghqohQ92niQBmW/j3u3HKkn\r\nhTo4+rZGXMqPOX9PRXRFnijLuXcbhwtPnrLAVMMoWKCj1Bt//MDIJjktkZ2n\r\nptDkvRI++tXG9bESB5BpronQ1kubrE+Z2xnjsJOm1BT2HHYbvrkqqgQQaJRy\r\noScQ95Yz2grp//x8PFb2n1vy/94E4ebkJtk=\r\n=oCnE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHv6nK4XNOCMM7NDtEzVDh70EE1W0S3qp/XQBtW4kLgxAiBRKXwCi9uiPTAqhMbsS6RnoIU/kIAWFrZ+2G67WpyP1w=="}]},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"},{"name":"alois-beto","email":"aguichard@betomorrow.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_2.0.0-alpha8_1647211345719_0.7804475766834245"},"_hasShrinkwrap":false},"1.7.2":{"name":"micro-observables","version":"1.7.2","description":"A simple Observable library that can be used for easy state management in React applications.","author":{"name":"BeTomorrow"},"license":"MIT","keywords":["observable","typescript","react","state","hook"],"main":"dist/index.js","typings":"dist/index.d.ts","module":"dist/micro-observables.esm.js","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test","lint":"tsdx lint","prepublishOnly":"tsdx build && tsdx test"},"engines":{"node":">=10"},"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"homepage":"https://github.com/BeTomorrow/micro-observables#readme","husky":{"hooks":{"pre-commit":"tsdx lint"}},"prettier":{"printWidth":120,"trailingComma":"es5"},"peerDependencies":{"react":">=16.8.0"},"devDependencies":{"@types/hoist-non-react-statics":"^3.3.1","@types/react":"^16.9.41","husky":"^4.2.5","tsdx":"^0.14.1","tslib":"^2.0.0","typescript":"^4.0.3"},"dependencies":{"hoist-non-react-statics":"^3.3.2"},"gitHead":"8eb7936d07e6719f9d26c3d93bef2e5e31acbea0","bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"_id":"micro-observables@1.7.2","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-NLXMvBpeXO/QAJ9r2SoxAE9qJXvECMRnKXkQrjZ5TNy0bUKawrgyUafHbJpFnP3j+DTehjPxJU6VXnNMjvicNA==","shasum":"f8fa47bdd9a78d7a45af8b86661a7fad0acecfd0","tarball":"https://registry.npmjs.org/micro-observables/-/micro-observables-1.7.2.tgz","fileCount":32,"unpackedSize":193117,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBXUrwf7zj96j8htuR+cQrZMBmBPfKnGwRBSmLzhqmjVAiBYsSWCtH2bzV8zm9w9NkA9hozytYN8q6B3Sp2mdAK36g=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJidDcxACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmof0Q//e4Al00xxyA+4sKLacY/jSA+0R7ny9IlqpC9HJs6o/bK61c98\r\niZyoXuzPBryoUyQoxAwoNYfkmpzSovJLhkAX8iYB6JxX+78xunJNtA/rbwRR\r\nIcga6t5ScELPyBIIYh640org7o41vXhAcIM86L3Vc2AcTmrOBxBK/+Wy9sR8\r\npW0uHxuVBmKioBOUw4czRmYRbgJj4NQB2LZplGRv78MNLjrb01xLEZZ7dmCj\r\nsvMj7UpDsoK4teNnCuOpr+gE1K4RPcuY/30CC/L/ScY17j4DE4G6GwwAFSI3\r\nz4JQsvGk9u2LKX1N6wM3usTdO1t5ZMAXAN5Y0izR+4ubr3KE/yE5DbX1ULz5\r\nGSaDMYCpEDAERV/Jo7mDT8h4BfkQtmk3NUqSc9i9TtSjraZeBHfRn3hhjy7L\r\nw20IXd9XRnm6Dvf2BDRPWl0iiuMlfy5r9ySkI9EG91sOpId1VLJbWLtktXJA\r\nQcztvNx2lXMxdRGte9TPcN4CLoZyybHkjDG08G+7Fy4ECqNeHF1NT2HcbBN2\r\neiYDS2Uh3a4FmJY+GH4OPx9dGthFJA3PAQ0Kia7QEbOEk0EEcTmugaHbg9OQ\r\nHCK9UStIitlydKQMNoGpsuFHInRn2nRaSQB+7KWOINAd+3Lsc/0ut6w6BwV8\r\nglZXRaGgQYcf4lpD8l36zzJHdksms5oLhcY=\r\n=uSGb\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"simontreny","email":"simon.treny@gmail.com"},"directories":{},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"},{"name":"alois-beto","email":"aguichard@betomorrow.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/micro-observables_1.7.2_1651783473276_0.4064921574204192"},"_hasShrinkwrap":false}},"time":{"created":"2019-10-21T16:09:39.644Z","1.0.0":"2019-10-21T16:09:39.792Z","modified":"2022-05-09T07:22:07.215Z","1.0.1":"2019-10-21T16:25:01.715Z","1.0.2":"2019-11-28T08:55:33.602Z","1.0.3":"2019-11-28T10:20:08.362Z","1.1.0":"2019-12-18T17:29:43.348Z","1.2.0":"2019-12-19T09:17:40.536Z","1.2.1":"2019-12-31T08:11:29.154Z","1.2.2":"2020-01-10T10:14:09.525Z","1.2.3":"2020-01-21T11:58:23.964Z","1.2.4":"2020-01-26T16:09:55.120Z","1.2.5":"2020-02-27T15:21:26.772Z","1.2.6":"2020-02-27T15:56:43.033Z","1.2.7":"2020-02-27T16:07:10.712Z","1.2.8":"2020-02-28T08:00:19.285Z","1.3.0":"2020-03-11T15:57:38.945Z","1.3.1":"2020-03-23T22:41:05.287Z","1.3.2":"2020-03-30T21:06:01.411Z","1.3.3":"2020-04-06T12:22:17.631Z","1.4.0-rc0":"2020-04-29T08:47:42.040Z","1.4.0-rc1":"2020-05-24T20:33:21.439Z","1.4.0-rc2":"2020-05-27T05:55:51.594Z","1.4.0-rc3":"2020-06-10T21:29:47.294Z","1.4.0-rc4":"2020-06-23T16:28:41.284Z","1.4.0-rc5":"2020-06-23T16:38:08.701Z","1.4.0":"2020-06-26T08:06:08.376Z","1.5.0-rc1":"2020-06-26T15:55:50.964Z","1.5.0-rc2":"2020-06-26T21:23:13.300Z","1.5.0-rc3":"2020-06-26T21:30:13.106Z","1.5.0-rc4":"2020-06-28T14:08:27.802Z","1.5.0-rc5":"2020-07-03T12:45:34.846Z","1.5.0-rc6":"2020-07-06T08:47:24.941Z","1.5.0-rc7":"2020-07-06T10:23:48.802Z","1.5.0":"2020-08-15T07:47:27.694Z","1.6.0-rc1":"2020-10-16T14:00:32.457Z","1.6.0-rc2":"2020-10-16T14:21:03.870Z","1.6.0-rc3":"2020-10-19T11:01:26.189Z","1.6.0-rc4":"2020-11-26T06:42:25.198Z","1.6.0-rc5":"2020-11-26T09:46:38.039Z","1.6.0-rc6":"2020-11-26T10:19:07.597Z","1.6.0":"2020-11-26T22:13:26.306Z","1.7.0-rc1":"2020-11-29T10:09:38.683Z","1.7.0-rc2":"2020-11-29T15:35:32.299Z","1.7.0-rc3":"2020-11-29T16:32:38.137Z","1.7.0":"2021-01-01T07:34:32.991Z","1.7.1-rc1":"2021-05-20T22:19:28.079Z","1.7.1-rc2":"2021-10-01T20:07:49.888Z","2.0.0-alpha1":"2021-12-05T23:36:22.440Z","2.0.0-alpha2":"2021-12-06T23:36:49.108Z","2.0.0-alpha3":"2021-12-09T22:13:36.714Z","2.0.0-alpha4":"2021-12-09T23:10:33.591Z","1.7.1":"2022-03-12T11:49:53.025Z","2.0.0-alpha5":"2022-03-12T11:53:51.831Z","2.0.0-alpha6":"2022-03-13T07:53:11.131Z","2.0.0-alpha7":"2022-03-13T08:01:53.628Z","2.0.0-alpha8":"2022-03-13T22:42:25.850Z","1.7.2":"2022-05-05T20:44:33.463Z"},"maintainers":[{"name":"simontreny","email":"simon.treny@gmail.com"},{"name":"alois-beto","email":"aguichard@betomorrow.com"}],"homepage":"https://github.com/BeTomorrow/micro-observables#readme","keywords":["observable","typescript","react","state","hook"],"repository":{"type":"git","url":"git+https://github.com/BeTomorrow/micro-observables.git"},"author":{"name":"BeTomorrow"},"bugs":{"url":"https://github.com/BeTomorrow/micro-observables/issues"},"license":"MIT","readme":"# Micro-observables\n\n_A simple Observable library that can be used for easy state-management in React applications._\n\n## Features\n\n- **💆‍♂️ Easy to learn:** No boilerplate required, write code as you would naturally. Just wrap values that you want to expose to your UI into observables. Micro-observables only exposes a few methods to create and transform observables\n- **⚛️ React support:** Out-of-the-box React support based on React Hooks and higher-order components\n- **🐥 Lightweight:** The whole source code is made of less than 400 lines of code, resulting in a **6kb** production bundle\n- **🔥 Performant:** Observables are evaluated only when needed. Micro-observables also supports [React and React Native batching](#react-batching), minimizing the amount of re-renders\n- **🔮 Debuggable:** Micro-observables does not rely on ES6 proxies, making it easy to identify lines of code that trigger renders. Code execution is easy to follow, making debugging straightforward\n- **🛠 TypeScript support:** Being written entirely in TypeScript, types are first-class citizen\n\n## Introduction\n\nIn micro-observables, observables are objects that store a single value. They are used to store a **piece of state** of your app. An observable notifies listeners each time its value changes, triggering a re-render of all components that are using that observable for example.\n\nObservables can be easily derived into new observables by applying functions on them, such as `select()`, `onlyIf()` or `default()`.\n\nMicro-observables works great in combination with React thanks to the use of the `useObservable()` hook or the `withObservables` higher-order component. It can be used as a simple yet powerful alternative to [Redux](https://redux.js.org) or [MobX](https://mobx.js.org).\n\nMicro-observables has been inspired by the simplicity of [micro-signals](https://github.com/lelandmiller/micro-signals). We recommend checking out this library for event-driven programming.\n\n**Note:** If you are used to RxJS, you can think of micro-observables as a React-friendly subset of RxJS exposing only the `BehaviorSubject` class.\n\n## Basic usage\n\n```ts\nimport assert from \"assert\";\nimport { observable } from \"micro-observables\";\n\nconst favoriteBook = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst favoriteAuthor = favoriteBook.select(book => book.author);\n\nassert.deepEqual(favoriteBook.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\nassert.equal(favoriteAuthor.get(), \"Kipling\");\n\nconst receivedAuthors: string[] = [];\nfavoriteAuthor.subscribe(author => receivedAuthors.push(author));\n\nfavoriteBook.set({ title: \"Pride and Prejudice\", author: \"Austen\" });\nassert.deepEqual(receivedAuthors, [\"Austen\"]);\n\nfavoriteBook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.deepEqual(receivedAuthors, [\"Austen\", \"Shakespeare\"]);\n```\n\n## Using micro-observables with React\n\nMicro-observables works great with React and can be used to replace state-management libraries such as Redux or MobX. It allows to easily keep components in sync with shared state by storing pieces of state into observables. The `useObservable()` hook or `withObservables` higher-order component can be used to access these values from a component.\n\n### Obligatory TodoList example\n\n```tsx\ntype Todo = { text: string; done: boolean };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n  readonly pendingTodos = this._todos.select(todos => todos.filter(it => !it.done));\n\n  addTodo(text: string) {\n    this._todos.update(todos => [...todos, { text, done: false }]);\n  }\n\n  toggleTodo(index: number) {\n    this._todos.update(todos => todos.map((todo, i) => (i === index ? { ...todo, done: !todo.done } : todo)));\n  }\n}\n\nconst todoService = new TodoService();\ntodoService.addTodo(\"Eat my brocolli\");\ntodoService.addTodo(\"Plan trip to Bordeaux\");\n\nexport const TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      <TodoListHeader />\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n      <AddTodo />\n    </div>\n  );\n};\n\nconst TodoListHeader: React.FC = () => {\n  const pendingCount = useObservable(todoService.pendingTodos.select(it => it.length));\n  return <h3>{pendingCount} pending todos</h3>;\n};\n\nconst TodoItem: React.FC<{ todo: Todo; index: number }> = ({ todo, index }) => {\n  return (\n    <li style={{ textDecoration: todo.done ? \"line-through\" : \"none\" }} onClick={() => todoService.toggleTodo(index)}>\n      {todo.text}\n    </li>\n  );\n};\n\nconst AddTodo: React.FC = () => {\n  const input = useRef<HTMLInputElement>(null);\n\n  const addTodo = (event: React.FormEvent) => {\n    event.preventDefault();\n    todoService.addTodo(input.current!.value);\n    input.current!.value = \"\";\n  };\n\n  return (\n    <form onSubmit={addTodo}>\n      <input ref={input} />\n      <button>Add</button>\n    </form>\n  );\n};\n```\n\nThis example can be run on [CodeSandbox](https://codesandbox.io/s/hopeful-sea-jrd9e?file=/src/TodoList.tsx).\n\n### React Batching\n\nMicro-observables supports React batched updates: when modifying an observable, all re-renders caused by the changes from the observable and its derived observables are batched, minimizing the total amount of re-renders.\n\nAnother important benefit of React Batching is that it ensures **consistency** in renders: you can learn more about this on [MobX Github](https://github.com/mobxjs/mobx-react/pull/787#issuecomment-573599793).\n\nBy default, batching is disabled as it depends on the platform your app is targeting. To enable it, import one of these files before using micro-observables (typically in your `index.js` file):\n\n**For React DOM:** `import \"micro-observables/batchingForReactDom\"`\n\n**For React Native:** `import \"micro-observables/batchingForReactNative\"`\n\n**For other platforms:** You can use the custom batching function provided by the platform by calling the `setBatchedUpdater()` function from micro-observables.\n\n## API\n\nIn micro-observables, there are two types of observables: `WritableObservable` and `Observable`. A `WritableObservable` allows to modify its value with the `set()` or `update()` methods. An `Observable` is read-only and can be created from a `WritableObservable` with `readOnly()`, `select()`, `onlyIf()` and other methods.\n\n### Functions\n\n#### observable(initialValue): WritableObservable\n\n`observable(initialValue)` is a convenient function to create a `WritableObservable`. It is equivalent to `new WritableObservable(initialValue)`.\n\nWrapping a value with the `observable()` function is all is needed to observe changes of a given value.\n\n**Note:** `initialValue` can be another observable. In this case, the new observable will be automatically updated when `initialValue` changes.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n```\n\n### Instance Methods\n\n#### Observable.get()\n\nReturn the value contained by the observable without having to subscribe to it.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nassert.equal(book.get(), \"The Jungle Book\");\n```\n\n#### WritableObservable.set(newValue)\n\nSet the new value contained by the observable. If the new value is not equal to the current one, listeners will be called with the new value.\n\n```ts\nconst book = observable(\"The Jungle Book\");\nbook.set(\"Pride and Prejudice\");\nassert.equal(book.get(), \"Pride and Prejudice\");\n```\n\n**Note:** `newValue` can be another observable. In this case, the observable will be automatically updated when `newValue` changes.\n\n#### WritableObservable.update(updater: (value) => newValue)\n\nConvenient method to modify the value contained by the observable, using its current value. It is equivalent to `observable.set(updater(observable.get()))`. This is especially useful to work with collections or to increment values for example.\n\n```ts\nconst books = observable([\"The Jungle Book\"]);\nbooks.update(it => [...it, \"Pride and Prejudice\"]);\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\"]);\n```\n\n#### Observable.subscribe(listener: (value, prevValue) => void)\n\nAdd a listener that will be called when the observable's value changes. It returns a function to call to unsubscribe from the observable. Each time the value changes, all the listeners are called with the new value and the previous value. **Note:** Unlike other observable libraries, the listener is not called immediately with the current value when `subscribe()` is called.\n\n```ts\nconst book = observable(\"The Jungle Book\");\n\nconst received: string[] = [];\nconst prevReceived: string[] = [];\nconst unsubscribe = book.subscribe((newBook, prevBook) => {\n  received.push(newBook);\n  prevReceived.push(prevBook);\n});\nassert.deepEqual(received, []);\nassert.deepEqual(prevReceived, []);\n\nbook.set(\"Pride and Prejudice\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n\nunsubscribe();\nbook.set(\"Hamlet\");\nassert.deepEqual(received, [\"Pride and Prejudice\"]);\nassert.deepEqual(prevReceived, [\"The Jungle Book\"]);\n```\n\n#### WritableObservable.readOnly()\n\nCast the observable into a read-only observable without the `set()` and `update()` methods. This is used for better encapsulation, preventing outside modifications when an observable is exposed.\n\n```ts\nclass BookService {\n  private _book = observable(\"The Jungle Book\");\n\n  readonly book = this._book.readOnly();\n}\n```\n\n**Note:** This method only makes sense with TypeScript as the returned observable is the same unchanged observable.\n\n#### Observable.select(selector: (value) => selectedValue)\n\nCreate a new observable with the result of the given selector applied on the input value. Each time the input observable changes, the returned observable will reflect this changes.\n\n```ts\nconst book = observable({ title: \"The Jungle Book\", author: \"Kipling\" });\nconst author = book.select(it => it.author);\nassert.equal(author.get(), \"Kipling\");\nbook.set({ title: \"Hamlet\", author: \"Shakespeare\" });\nassert.equal(author.get(), \"Shakespeare\");\n```\n\n**Note:** The provided `selector` function can return another observable. In this case, the created observable will get its value from the returned observable and will be automatically updated when the value from the returned observable changes.\n\n#### Observable.onlyIf(predicate: (value) => boolean)\n\nCreate a new observable that is only updated when the value of the input observable passes the given predicate. When `onlyIf()` is called, if the current value of the input observable does not pass the predicate, the new observable is initialized with `undefined`\n\n```ts\nconst counter = observable(0);\nconst even = counter.onlyIf(it => it % 2 === 0);\nconst odd = counter.onlyIf(it => it % 2 === 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), undefined);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 0);\nassert.equal(odd.get(), 1);\n\ncounter.update(it => it + 1);\nassert.equal(even.get(), 2);\nassert.equal(odd.get(), 1);\n```\n\n#### Observable.default(defaultValue)\n\nTransform the observable into a new observable that contains the value of the input observable if it is not `undefined` or `null`, or `defaultValue` otherwise. It is equivalent to `observable.select(val => val ?? defaultValue)`. This is especially useful in combination with `onlyIf()` to provide a default value if current value does not initially pass the predicate.\n\n```ts\nconst userLocation = observable<string | null>(null);\nconst lastSeenLocation = userLocation.onlyIf(it => !!it).default(\"Unknown\");\nassert.equal(lastSeenLocation.get(), \"Unknown\");\n\nuserLocation.set(\"Paris\");\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(null);\nassert.equal(lastSeenLocation.get(), \"Paris\");\n\nuserLocation.set(\"Bordeaux\");\nassert.equal(lastSeenLocation.get(), \"Bordeaux\");\n```\n\n#### Observable.toPromise()\n\nConvert the observable into a promise. The promise will be resolved the next time the observable changes. This is especially useful in order to `await` a change from an observable.\n\n```ts\nconst age = observable(34);\n(async () => {\n  await age.toPromise();\n  console.log(\"Happy Birthday!\");\n})();\nage.set(35);\n```\n\n### Static Methods\n\n#### Observable.select([observable1, observable2, ...], selector: (val1, val2...) => selectedValue)\n\nTake several observables and transform them into a single observable with the result of the given selector applied on the input values. Each time one of the input observables changes, the returned observable will reflect this changes. This is a more generic version of the `observable.select()` instance method, that can takes several observables.\n\n```ts\nconst author = observable(\"Shakespeare\");\nconst book = observable(\"Hamlet\");\nconst bookWithAuthor = Observable.select([author, book], (a, b) => ({\n  title: b,\n  author: a,\n}));\nassert.deepEqual(bookWithAuthor.get(), { title: \"Hamlet\", author: \"Shakespeare\" });\n\nbook.set(\"Romeo and Juliet\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"Romeo and Juliet\", author: \"Shakespeare\" });\n\nauthor.set(\"Kipling\");\nbook.set(\"The Jungle Book\");\nassert.deepEqual(bookWithAuthor.get(), { title: \"The Jungle Book\", author: \"Kipling\" });\n```\n\n#### Observable.merge(observables)\n\nTransform an array of observables into a single observable containing an array with the values from each observable.\n\n```ts\nconst booksWithId = [\n  { id: 1, book: observable(\"The Jungle Book\") },\n  { id: 2, book: observable(\"Pride and Prejudice\") },\n  { id: 3, book: observable(\"Hamlet\") },\n];\nconst books = Observable.merge(booksWithId.map(it => it.book));\nassert.deepEqual(books.get(), [\"The Jungle Book\", \"Pride and Prejudice\", \"Hamlet\"]);\n```\n\n#### Observable.latest(observable1, observable2, ...)\n\nTake several observables and transform them into a single observable containing the value from the last-modified observable. The returned observable is initialized with the value from the first given observable.\n\n```ts\nconst lastMovie = observable(\"Minority Report\");\nconst lastTvShow = observable(\"The Big Bang Theory\");\nconst lastWatched = Observable.latest(lastMovie, lastTvShow);\nassert.equal(lastWatched.get(), \"Minority Report\");\n\nlastTvShow.set(\"Game of Thrones\");\nassert.equal(lastWatched.get(), \"Game of Thrones\");\n\nlastMovie.set(\"Forrest Gump\");\nassert.equal(lastWatched.get(), \"Forrest Gump\");\n```\n\n#### Observable.compute(compute: () => value)\n\n`Observable.compute()` is your **silver bullet** when it is too difficult to create a new observable with the usual `select()`, `onlyIf()` or `latest()` methods. It is especially useful when dealing with complex data structures. It takes a function that computes a new value by directly accessing values from other observables and it returns a new observable containing the result of this computation.\n\n**How it works:** Each time the observable is evaluated, it calls the provided `compute` function and automatically tracks the observables that are used during the computation (i.e. those on which `get()` is getting called). It then registers these observables as input, ensuring that the new observable is updated each time one of them changes. If you are familiar with MobX, it works the same way as the `@computed` observables.\n\n**Note:** There is a slight performance impact of using `Observable.compute()` as it has to track and update the inputs dynamically. But unless you're dealing with thousands of computed observables, it should not be noticeable.\n\n```ts\nconst authors = new Map([\n  [0, observable(\"Kipling\")],\n  [1, observable(\"Shakespeare\")],\n  [2, observable(\"Austen\")],\n]);\nconst books = observable([\n  { title: \"The Jungle Book\", authorId: 0 },\n  { title: \"Pride and Prejudice\", authorId: 2 },\n  { title: \"Persuasion\", authorId: 2 },\n]);\nconst booksWithAuthors = Observable.compute(() =>\n  books.get().map(book => ({ title: book.title, author: authors.get(book.authorId).get() }))\n);\nassert.deepEqual(booksWithAuthors.get(), [\n  { title: \"The Jungle Book\", author: \"Kipling\" },\n  { title: \"Pride and Prejudice\", author: \"Austen\" },\n  { title: \"Persuasion\", author: \"Austen\" },\n]);\n```\n\n#### Observable.fromPromise(promise, onError?: (error) => value)\n\nConvert the promise into an observable. The observable is initialized with `undefined` and will be updated with the value of the promise when it is resolved. If the promise is rejected, the optional `onError` function is called with the error and should return the value to assign to the observable. If no `onError` function is provided, the observable keeps its `undefined` value.\n\n```tsx\nasync function fetchBook(title: string): Promise<Book> {\n  // ...\n}\n\nconst book = Observable.fromPromise(fetchBook(\"The Jungle Book\"));\nassert.equal(book.get(), undefined);\nbook.subscribe(book => console.log(`Retrieved book: ${book}));\n```\n\n#### Observable.batch(block: () => void)\n\nGroup together several observable modifications. It ensures that listeners from any derived observable are only called once which might be useful for data consistency or for performance.\n\nAdditionally, if React batching is enabled, it batches re-renders together. You can learn more about React batching and how to enable it [here](#react-batching).\n\n```tsx\nconst numbers = [...Array(10)].map((_, index) => observable(index));\nconst total = Observable.merge(numbers).select(num => num.reduce((a, b) => a + b));\nexpect(total.get()).toStrictEqual(45);\n\n// Listeners of \"total\" will only be called once, with the final result.\n// Without batching(), it would have been called 10 times\ntotal.subscribe(val => assert.equal(val, 65));\nObservable.batch(() => numbers.forEach(num => num.update(it => it + 1)));\n```\n\n## React Integration\n\n### Hooks\n\n#### useObservable(observable)\n\nReturn the value of the observable and trigger a re-render when the value changes.\n\n```tsx\nconst TodoList: React.FC = () => {\n  const todos = useObservable(todoService.todos);\n  return (\n    <div>\n      {todos.map((todo, index) => (\n        <TodoItem key={index} todo={todo} />\n      ))}\n    </div>\n  );\n};\n```\n\n#### useMemoizedObservable(factory: () => Observable, deps: any[])\n\nShortcut for `useObservable(useMemo(factory, deps))`. Return the value of the observable created by the `factory` parameter and automatically trigger a re-render when its value changes.\n\nThe `factory` function is evaluated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the `factory` function being called only once.\n\n**Note:** `useMemoizedObservable()` is an optimized version of `useObservable()` that avoids recreating a new observable and reevaluating it at each render. Most of the time, you actually don't even need it, creating an observable is a fast operation and if your observable evaluation does not require heavy computation, you can use `useObservable()` directly instead.\n\n```tsx\ntype User = { id: string; displayName: string };\ntype Todo = { text: string; completed: boolean; assigneeId: string };\n\nclass TodoService {\n  private _todos = observable<readonly Todo[]>([]);\n\n  readonly todos = this._todos.readOnly();\n\n  getTodosAssignedTo(assigneeId: string): Observable<Todo[]> {\n    return this._todos.select(todos => todos.filter(it => it.assigneeId === assigneeId));\n  }\n}\n\nconst TodoList: React.FC<{ assigneeId: string }> = ({ assigneeId }) => {\n  const todos = useMemoizedObservable(() => todoService.getTodosAssignedTo(assigneeId), [assigneeId]);\n  return (\n    <div>\n      <ul>\n        {todos.map((todo, index) => (\n          <TodoItem key={index} todo={todo} index={index} />\n        ))}\n      </ul>\n    </div>\n  );\n};\n```\n\n#### useComputedObservable(compute: () => value, deps?: any[])\n\nShortcut for `useMemoizedObservable(() => Observable.compute(compute), deps))`. Create a new observable with `Observable.compute()` and automatically trigger a re-render when the result of the `compute` function changes.\n\nThe observable is recreated each time one of the values in `deps` changes. If unspecified, `deps` defaults to `[]`, resulting in the observable being created only once.\n\n### Higher Order Component\n\n#### withObservables(Component, mapping): InjectedComponent\n\nHooks cannot be used in class components. In this case, you can use the `withObservables` HOC in order to inject values from observables into props of a component. It works the same as Redux's `connect()` function as it takes a component and a props-to-observables mapping.\n\n`mapping` can either be a plain mapping object of the form `{ props1: observable1, props2: observable2 }`, or it can be a function taking the `ownProps` of the component and returning a plain mapping object.\n\n```tsx\ninterface Props {\n  assigneeId: string;\n}\n\ninterface InjectedProps {\n  readonly todos: Todo[];\n}\n\nclass TodoList extends React.Component<Props & InjectedProps> {\n  render() {\n    return (\n      <div>\n        <ul>\n          {todos.map((todo, index) => (\n            <TodoItem key={index} todo={todo} index={index} />\n          ))}\n        </ul>\n      </div>\n    );\n  }\n}\n\nconst mapping = (ownProps: Props) => ({\n  todos: todoService.getTodosAssignedTo(ownProps.assigneeId),\n});\n\nexport default withObservables(TodoList, mapping);\n```\n","readmeFilename":"README.md","description":"A simple Observable library that can be used for easy state management in React applications."}