{"_id":"react-modelx","_rev":"85-8a4cabf93b4b64d405651fa52f6ec567","name":"react-modelx","dist-tags":{"latest":"2.5.3","unstable":"2.4.1-unstable.2","next":"2.0.0"},"versions":{"1.0.0-alpha":{"name":"react-modelx","version":"1.0.0-alpha","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react","model","state"],"author":{"name":"ArrayZoneYour"},"license":"MIT","dependencies":{"react":"16.7.0-alpha.2","react-dom":"16.7.0-alpha.2"},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"gitHead":"c04ee4f4e943f0e70c0be7de80f0fdec24061c18","_id":"react-modelx@1.0.0-alpha","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-33zNvlPi0u0Xj2XJ+SFApo5FRmYpHCu0wZIN26fhw4PdWElu0MxHYQsOvBxmTo79hUSPm4JCexMJTovuPqhuag==","shasum":"978397ebd11cbc0119770e1d3965b9d8241527b1","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.0-alpha.tgz","fileCount":21,"unpackedSize":220660,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcCNpDCRA9TVsSAnZWagAAdBYP/1EGGu0XMm3QTSej0+mb\nRBTTRrZHyzqMpBJab/yoKlSCbEs4xFHXjRCnArda9y0TMR20Ndt1hwgi2kBz\nkWJx3Rcvqw+PDpHPRqPgcF+ZJcTKa6r7Q/lCqhn0K59P+F+sbMpiuP1n9aJj\nikW/uV/dkUJ6Jz1woO28DF53oCHWrA6GxIeFfSALWZ+PW1HYCbqXzcCw17fy\njnXjW8qoayRr8dxqCOI+sqTu3hx77fz37WEoHEddVgglEFPd8hhRzrjxLaq1\nSq5WPJePhkerrfqYzpbpvNkMuIM3TNY9fHAKVofPefmczpUkD91ahOCM1Guj\nbpveFRosSL5zhrPuS3ZHStJtTPTnNhmMW43DzPWIR/Df18GR10IWshnAFsk9\ngxEYPk+fEcqqCZBHJOvFmA3HGiCrIHq8Cow0W6/wgNZY4G/E7ba0ABXxz33x\nfRHPpShNoL1jRZtO46D863L+pf/4ifxNP9Aug5tQc5xxHZZ45/2fEAdrk65D\nEH1+8oopDsIxHciAKi07WfQIRDWarX39msTRD3DYZCd1oHKGZ4JM0/pZ/nS2\nH7YvFoaj4fFIn2Y8AUr0/h4ht7+11dpqMHKdqI8yGBsfJAzLXiv16J51SBAc\nm/caO0Z2C+D0r779vxLiGF2LTJn265vKAv0QMPHBZnTGCnGo5LiSSc4KPqRA\noEZI\r\n=W3Db\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC3lIyiOJdCDS4Bqz9W0VXtjzLiQe7p2t/XMSnIdK5jUgIhANeS/uVyxE60FnTXTSAoKNWU4ovgauqP1zvHb9iBCWmq"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.0-alpha_1544084034422_0.3936398179920746"},"_hasShrinkwrap":false},"1.0.0-alpha.0":{"name":"react-modelx","version":"1.0.0-alpha.0","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react-modelx","react-model","react","model","state"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"react":"16.7.0-alpha.2","react-dom":"16.7.0-alpha.2"},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"gitHead":"52a544eee562b4e252c92a24d5d6aee36514eb63","_id":"react-modelx@1.0.0-alpha.0","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-KgCBnolTybvvjEZQx1IPESOcPpMV2f3Dm/sDgvAE/6IxUTGXY8SryOniXzvCdRNHwMsRZ0OHGreGNgYILkRsqg==","shasum":"98b985af6d1fccb099d6315d7f443559cb9659b9","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.0-alpha.0.tgz","fileCount":21,"unpackedSize":220732,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcCN75CRA9TVsSAnZWagAA7tsP/AkzpfReC0LC3z51r6yS\nPVJcsY8AKVoApnv8DZAhgQzsaQvGzumMsnOR6Gx6EGrjZghD7o89TkCTH8tH\n2/LfO0BDBzIuUx4k+PlXu1Rxrqpx1Cp0yHslsvDmZgOlT+pnQvkfMfEcf8GU\nLp1u8FYcUXKWHy7TUc+K0NTB8usxsUsd4gBq8iVltbuxDxPO4V0G0WvT19gV\nFlZHSAeAFwMexUwAzPKzlHMjB0SFt2VvhBuIgVcFUWkf+WOVoRzwxFeiY1Ja\nArCxYNM/aPNMNKfcI+gJnJwfSBzQeEQeQoK8KnLQM2KPZeUht53sVVMw9nh5\nYvYo/DRs0nGs8cpfDUkE3LANzGSZar8Zv5XmyX/7pUwueFz0PViMH7BbHFe+\n21m1nU4uimP3fsUg3bF7x8n1K2BbZsE5RfF3amdJoGk6eaRyBxKEPtQ8caHO\nK7PtS5UomjULN8Zhq3uVs+eMkL78II4O1lmtwXaHqihEEqZGCk/XIKEoYMwa\nsTlZQK2UeopqbstHfOdIa7HhaIaU8Zuyw+9D0Gv5pZjwXByDCCGrEmtHKKVl\nwX86jVuIAuH0mn7i07aCpthyfVjjsOfo4PsggOk8TmfwiZ0Vwcgt6Ew/Z624\n+tAzFcpJb6Xy/PO++5s2moa0KK3q/avGojNPbGD4Om/Cs8FVeKc0q9bvkJeW\nCpls\r\n=Ezqr\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC7CRowdTiX6Wc2rY3LxyVX48k7PMr+tY0/TPdsRlVEXAiBeHEn1PLFb06GJRAZ0N57qurX48ECGylpwfIhZZs41ww=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.0-alpha.0_1544085240612_0.49003680564163044"},"_hasShrinkwrap":false},"1.0.0-alpha.1":{"name":"react-modelx","version":"1.0.0-alpha.1","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react-modelx","react-model","react","model","state"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"react":"16.7.0-alpha.2","react-dom":"16.7.0-alpha.2"},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"52a544eee562b4e252c92a24d5d6aee36514eb63","_id":"react-modelx@1.0.0-alpha.1","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-TpMl/iyqtpt3LrkPlOAyR4XgVvu2LGJSKpU9JowGo5D5tpmJI7SIaa/8B40QSTaenP42lf3mhbIi3GAargVtpQ==","shasum":"4c07468fbd4b678fbd413a450d9300c94b41c36f","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.0-alpha.1.tgz","fileCount":21,"unpackedSize":220932,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcCODdCRA9TVsSAnZWagAATo4P/jNu37Aernz6t0VpH7uY\nTM90TQ9Je8gO4eeHDV/keswrDT4mq8uKLcDE3ngJ43F9/3Yo5OiT7iTJwvjb\nyRhrm11Jr6pv1ArIlO8HvkRhyGOwmNlL1+8OTHzYQ69ZRlFWbgqRMjrkAswO\ntLg1mq4107DxpggO6yECnLIUKYIfyLWaGeBzArv959JgalDYUGxm/WyXKWCm\nW5iqnZ3KDmRYWUO3TtC/CNmx8rSpxHkiqAO7tR+hUrbnwD2RypUbvwsg0FiQ\nwwbg8LjYlchCDJpePKEVVZpwdeHnWuORGuC4sQzOZj3Sui6oLgOKK9S+I+Tb\nCbby2EpyViUocsFRQxjlieGtAXQCuF7uDdMlkuJpsTxF0gOFwaLenEboIO0C\n3QVMte1DJNm9adtg0JTvro3aPZq2nGYcm65kjnQ2+ueZ3KH2f/X4hOvSKwab\nNUkBpFk5pR1kjo+CA6C0U2FVTkozq8Q7tGFreeN43Gz8Q6N68bAQaqD9Lv1l\n78RKb1m1T1CKUMKVrxlfMQfG7ZzmcpFdVyx9bkhBQUXc2rR7HzrfFY+QTRCc\nPalKvqlUTFncMZHmlDf8kig/80j+xN1gXBJC3J8HFUlUWknA6N2o1j+rDx/y\nRtJpWajg8OZao2ZyP1BG/B4SSIuKNsdrJ411uIIGSR0xvtTOtDd6AsIGzjVl\nvG/O\r\n=OQN8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFkn1uEkCRTCKJcwVDwg7IkTEVQiBVF+qsCLL3TVVxADAiAWUrdMkLN7WbC/R5V5RWjI42RhUqsIwVYf5ApMYtdfFQ=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.0-alpha.1_1544085721739_0.5380748607406058"},"_hasShrinkwrap":false},"1.0.0-alpha.2":{"name":"react-modelx","version":"1.0.0-alpha.2","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react-modelx","react-model","react","model","state"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"react":"16.7.0-alpha.2","react-dom":"16.7.0-alpha.2"},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"b3e8f4a8a145618cbf87fe10cd52a694dc0e988f","_id":"react-modelx@1.0.0-alpha.2","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-ttTK4r9u+2mjR/glCk5fdwiqq2xio1YGhfkwgT/DvO1UxUh0MxFqG8feZJiplClTXULjjrLwUVtn3lXalxASSQ==","shasum":"2b66b7492c5ae6f0baed316d9ee799d2138a98a8","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.0-alpha.2.tgz","fileCount":17,"unpackedSize":28872,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcCOmYCRA9TVsSAnZWagAATEsQAJU1L0eLyazhaeiARBWI\nvyt+Au09mk3STAkrn0QgTKaePI0TBmD3g89cuZ6VMdZ8nfJxKhBDWoLSJrJ/\n7w/jvN4JoJfZR+qznmO1t97ZXR81bBmSWM4EiPORpuGk889qyUaKJtxW0Y/o\nm2/S3LBTbL6fKWkDqjCM4Ohv9xSoKkbAYotDDKPcgFkxTqNBsTw0FktAKMVo\nnVf7VG8dYRNOAP0kKjirB4v7lQpTm+eSKw2izH2oMnwFazVp5Qllqv40m+Hj\nOgkT2l6dCTDXjCdRLhdYYbAggKm5fprWQ82hVCzlzVpc4G1F2WSrVq1e/gBu\ndYrMEfLBaLDGaurPZ2VFs0LM0WmQxSu/Q1/A3dCFRlfvlKocKcFmgyEpC22S\nuKtX8Jbdsm+3fFf+CKc33A9wAEsTHgIXRSbbsmQlz1Ox0QF+8KAtQNLKTJ/K\ncq7izpdBw7z6ggPSmUrOjaLh9UgkIxyTGq3Kcn0jD08xtMlHdFVEHXktNM/i\nZaOJF+9GjoWpPLgh7h2gNBmrJoJlBV0VmcrjvNE4z+tQZB4kBAE+hcwHa5g1\nKhA+z5bIiOGbLwCCoTdn5hRpviREfmxFfjPSHw1SzCKWRGrqdL2b2eT+31qZ\nICO0q1HPNXfLgXTrhOJYboVXrvYlOCsfi6u8dsVavXPh6FuZLs4iNdXTOkm1\n21GT\r\n=HCWB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCY47Kncl8dD8uH94IGSbtM6L9Pq75jNsbIJmxnP6yxrgIhAMTQZvnRCfgfDLGWRioAQ412qXkEur04t5HB2ZtaA428"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.0-alpha.2_1544087959606_0.6563388263069214"},"_hasShrinkwrap":false},"1.0.0-alpha.3":{"name":"react-modelx","version":"1.0.0-alpha.3","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react-modelx","react-model","react","model","state"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"react":"16.7.0-alpha.2","react-dom":"16.7.0-alpha.2"},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"2edc7f7eb881102c0702695672f819806f6833c4","_id":"react-modelx@1.0.0-alpha.3","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-W5nC4rTUuTMpgeBiFgnhFdeH6aJl6i2U9qCy1UePOE5ULKFy9sz4xKGR1isteSCKBEHO6TTGu2hIEZZoM7QYEw==","shasum":"8deabfd1ecc91118aa55774a8193ba78de9c1971","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.0-alpha.3.tgz","fileCount":17,"unpackedSize":30554,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcDInjCRA9TVsSAnZWagAATAEQAJuleYHs6P/HV+6Xfekh\nyxBy0UHbVm52vThG13Jk7q4LAhArWSrH0+Pg+Cpq07f3N4zB0p0srPlJVw27\nqKRdfE62QI/9TcdzRzbR6yK7Xblo5bnkX6v3uDFbF2E54THBbdSomxxMcjSU\ng/w/a+BGqKgF3hitTcF69Ad3KhS1J8ldvPoTWH//YyTJQlU/AaWMpP/yJYE/\nFqaia76vceiVn3D3me4j2bnfnMzgTFtRYmnLHFcwJEcjVF5kiIziRXH174sF\nWWSCKhaQHT/ZsYtEufp6c/CSUXuwOHOXMR2xLaJ6QdBMg/GBcFgxB9RGrdfv\nYwQ7vsKC1ZsJGjc9DSfhKVUOtRh7aT3fZSABR6gMMswAd2WrWzrCzTzXXD92\nGLWZeyDXMGdi2cUCWRplsd5n6W5ggOQEYdqrlQwBi6OaZkC7Drns+rlDF59a\n4BGHnTgvSfUh76lT0WntA0/ea6yDIEyGPdPPpZn5/fwGjF3QGy1rtsfn9JhI\nzqjN3IpqoFyg2ojwTuJ13DJQtV/rtyZy/t86NjucAgVbTt0GXQESQoO/Zhip\n0Vgr+UelqDu++FcYVJBNN4R9kZFAC/bfRhGRc/W8qASiPmHqlHwyUIEuTKDd\n0K3/gtOn6I5N32Xk3o164GF4UA6PjGwxCmFEjXqPfjxWTSubju2FhGd55c9O\n2CLy\r\n=bBDr\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCtqgg1ZhxLWnI/3xZlR1mFN2hJ+Gcj70Ou6IR6JiAdoAIgK8KHvgAazHQygEMPfrqgZfX3B3Yh+bOLVrciOMEufJ4="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.0-alpha.3_1544325602848_0.631473578163136"},"_hasShrinkwrap":false},"1.0.0-alpha.4":{"name":"react-modelx","version":"1.0.0-alpha.4","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react-modelx","react-model","react","model","state"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"react":"^16.7.0","react-dom":"^16.7.0"},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"c4be1c3e7ea281b14949c50043477e041facc0e1","_id":"react-modelx@1.0.0-alpha.4","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-I/hG96azZjfx6vrrcNMFrhSYLzrqKruEhHvZJ6J+G3jKwnt6RE0L9Dm4adHm4Gwf86o6teiEES3ipENXbgPcDA==","shasum":"90c6e8987c1c5a12f7a5e40f3e0e5554d1014154","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.0-alpha.4.tgz","fileCount":17,"unpackedSize":30615,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcHGwHCRA9TVsSAnZWagAA2EcQAIhzh2rT6kertaR9Sksk\n9yF+CIt4vAB0x683wps+xZDAqLZKghjmGqiYUvgQNzPWMQ9fh3xp83RjoSR5\nlc7GfwXckB7/Ypvwwmnj5K5OuCOpIoWenqIUZ4jhhGONu+n4jIkdfPNDauNW\ntaQnWQhTArS618Bv8+5nauMNi7elwO4kkweFICWIlkzkq6AZdzQ7Z52IVbnm\nBCmY0uAmEYbp9CjIw4/dbIj+SFwPXR6qMLo2lWkTRGSpruk8K3a/5NN3wHgx\nVx4USsS4GID63hTMB3GEgcdUrs1cvBTVmaIh4gTa3cDZ6p7BpyDs0fsHrohk\nE3fso5giO6ycCbxNeLb1InecURQYZoJkJrwkAQRksdjOc8JZUpv3EZGCG36z\ndqQ0l73+4NhRovCXXGqAkip6tdkWFQmDV67zXeluh0ivZ8bS8HZ6tQX+Ptkx\nfPtqD4MnXWdnb67997Bdtq+OKquwLj0LyiwiMvH5xZeQppGKr+lunI5k7LpP\nEUTIdCeQGixTqjaBJ0QMC8rPXJocMWAbZyek8JpqvZTECkPChyducpyDz2O4\nMA7xhP33hWEodpgOb0URD1U/prF72A3ZROGH+4F3+si+daHCoWv6MJeoPjrB\n8E3C22rfwfnh6MK3UBMq/OJvtyH1a+mikUVQEt7ICSOBlreKKxxkpY2UOM0D\n2d8m\r\n=sxtO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAqn5PF/s1bOGxXGERtLocUZnk/cVyV0Sm7H04ayK8J1AiAaNPFsntwdmXY2G3LC3wlbOI7umOklPOQpwGqyYa+sow=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.0-alpha.4_1545366535438_0.09899857834199488"},"_hasShrinkwrap":false},"1.0.0-alpha.5":{"name":"react-modelx","version":"1.0.0-alpha.5","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx","publish":"tsc && npm publish"},"keywords":["react-modelx","react-model","react","model","state"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"c4be1c3e7ea281b14949c50043477e041facc0e1","_id":"react-modelx@1.0.0-alpha.5","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-zCVk2ywpUccyjuvHamaoQpOr3OtmXgABo3t2v9c9ABKHsRfy0PNLI8yVgovujTbglvF9o+wN8zlqUdQC0XtfNg==","shasum":"512479d7911431c99193174bc2e81dd453094129","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.0-alpha.5.tgz","fileCount":18,"unpackedSize":33801,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcHIKZCRA9TVsSAnZWagAAh58P+wQi+G8imAPH/N4SG0Xo\niE11dfKMDPHco8F4btmsl7a2dNLpwy0GTjwvHzPpRpbOW1XO9c+r8XH51dxn\n/H2HHPB+NM8d9wPyUR6gICd4uMdxQTHGR/E652adZq72pferUWLOmg3tKgyZ\nS2H8p7NcsPWd5i6Rn1c11QPhVFmdnK/Quzm2nPmfSMWLrHYJ9Q2TVrxTUHin\nbsmDCG08xKJOCJPtdSDTqY0o6NQthtQJEfaF6c/8jf1g4N6DXSGcJ0EtYguP\n9AZwSsvR+KpcoTgCKVr1G4fa5DguNIobO8k3lmKSHkRgVyHpWNYjyxUYYd4V\nttB04H7+62rTEGFp7sGU53egz9dwMGLvjans+FELa3LNdZIQK2ZaXJyCvPlD\nvhXy517JwSw693I+xFdvsZrNpQOykm4pEXQPJJbO3QsQpY/MXA7JT9xtapCu\n75wCGLZKjpLqqFaXLq43tvpxaGlX6BPrj20FGb8mF6xE9IVI+uTZC2w9ymQX\ng5yB4JOGM3Ls6O76jlDJ6LNET4wM4bmR6PnxUGLxBBiYNPvj6bDI8piRZCco\nefW3tEKcGs0AuniM6pFi/frwIdWRj9YwZ8/8tunKp/hjA4gJsPejhvzMejJK\nJh8VPm1GVacXxwa07lt837sw+CyqSQwoElOXPWolYS8GVFAJuibALJtKPa4g\nUQKk\r\n=CSoo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICNoglv4XGfIZS7UOlXIbvJVfhL80idHeAHNxvbf41H0AiADoZfcRI1qokEzqziS8tfzUNHqdhLjbccYcrexDuwyQQ=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.0-alpha.5_1545372312239_0.10287949178619349"},"_hasShrinkwrap":false},"1.0.0-alpha.6":{"name":"react-modelx","version":"1.0.0-alpha.6","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx","publish":"tsc && npm publish"},"keywords":["react-modelx","react-model","react","model","state"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"c4be1c3e7ea281b14949c50043477e041facc0e1","_id":"react-modelx@1.0.0-alpha.6","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-aeNS3KlfNM5z1A43FboS2wM/Gvy4ucxMfHFI0S1n+OTz055YQwzQ6oAdv5D4GQc5sQaUx00ZN5CpGjW9qYzwxA==","shasum":"555872ffc7bc18f9acc45e89b120ffece1a17417","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.0-alpha.6.tgz","fileCount":18,"unpackedSize":33801,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcHIKrCRA9TVsSAnZWagAAFkcP/iQa7iKeEvAGxZ10X237\nT8X/A8YtsdNJEWBY/Du2ZlC8VfJcvyCd3DXSaLiea9OPTYL6V1D6HTmETIeo\nYoL/nmTSd4S6gdogZ4bFOG5BjlkrjvGEniW1wqrW7j7ov6gcH0lkvyM/D8kj\nXChoGD+6dK+HN6E7cCU1yHkceUKtRVEyvMBWq9GYRB7Hb2Zgq7OfZKJRFW6+\nt7BXXdErNpP+qVxaBN+ERE/dpeKcHGvjPj0cNs0l6Rqmu15HxQ+hZvb46jux\n9bu2wKYHFuRI8xxK6vGPxQF7IEd7YhXg6OBYpHG95OH8h+WHxEEnuUiSD5hS\nI/mSNfmt9Vaj2/pEBPh/LeUx+9lGiPTBIPn+x9l/4PsUrbxelpwKRK/ukwPW\nXXIaEFUUuxBnwTvUr5UcdcWvZPOzLS5DT/2R4/uNZ5vi/gf8XTidfg64G5X/\n7/cl/5ode1uuICAEBALq/HgcaJFQqjv9MrD1kJi8ouJ9EA+uf3WKg8Qn2CJA\nHztvgp2LoFyX8XMB6os/TJuoDMtQLqNnwbn/UrEv/ytvnU44jHNrEZKVeBbb\ndBpxW7fvcZsLK1UuBAFbp6oTgKu/qFgaT5AM6b3/Z1aomosKU0jfSX7G5XAb\nhHC9O6u2bcihkN1gVBdvQfAAmd2Nxs9P4HX6uqW/6ZUqqgffM8LEZAwXu9R3\nRs0g\r\n=XnB8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCOlD2dLhuwfevkyKGWxbaUB6gD3Sw/2PbwMwFjs3DB8AIhALkx1PVoAX+UmJitq3zW+4uu6VFSuxZIZ56A9nW3jWNT"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.0-alpha.6_1545372330777_0.7216237619826242"},"_hasShrinkwrap":false},"1.0.0-alpha.7":{"name":"react-modelx","version":"1.0.0-alpha.7","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx","publish":"tsc && npm publish"},"keywords":["react-modelx","react-model","react","model","state"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"8867a76257ad9ee56d94fc47907ac6fefb7134bf","_id":"react-modelx@1.0.0-alpha.7","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-9cJsrlyZz6RhRD2taWoqPTUYrzKdPKVcqYLLBJ/8aqYgv1pwwjIRpgYfBYpJ/bltBrTMMc2XTif3UKz46pwE4A==","shasum":"02d67aa015af859363398e6b631c6e209b646bb9","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.0-alpha.7.tgz","fileCount":18,"unpackedSize":33889,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcHKP6CRA9TVsSAnZWagAA44IP/R4QZr8UXQGn3sNrpDZD\nME3rrIkRzO1OSEN5mdeOEc/IdddINgbWw0WQa3e19qNpeogtbb3AUTSIrvEk\nqLx3F0YMjt76Oicmp2AGoXZSjPqq3b4KoOUc5qm2k0fEaGo0uP4rdWsedi+W\nsi+PpMKTdnQwXHVlVB2EvF1hYpm1dbUo/ovyhIUDfAicdVkUQzr5PaTvCVAl\nk+/jfmYqS2I+QOSuB52tCeoA+x4Pn5AyQtKSzStGOPeCPEgbEBxxiW6O8FYW\nx/0WsDgruxKQc6lfWeesJSknTtHDiFpOGEldzuAhgSZwOn2CsoojI8tMHHHK\nAt+oiQ8lpzvwCyUiV4jY4vyK7KWCoGFtzYEb2tvn9sqm+WzF4Pw6pc0ykljM\n1coytDB/H8rSLi+LDyFIbgZ3elMXNjP5Aom8xi278TUO6JDRtFFT1Wz1stDH\njOKWnpkVAm2zYndwZihGF6ugiXy8AY4QAF55LkZh70sInkDrI4EDrJ9AfWhT\nxKtXH6ATb+rBorrgjx3/huasxKuY25wOnvxV9PKQRfaWBQlwtYaODUTxpw41\ne/2Qa+++GQ7cgZ3jd+fzpw2OsmpPAk5QUEVdvOQpfZAy4j2U8UlnEUZXzU+i\nARldDM3uKhMIM9eslNPfZWNLJZe2trlaXBrd08jAbhAy6WZ/RWdjQfl+/2i/\nI/Hj\r\n=F5K8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHC5hgiVN/mXLs6r/Gtf0i6h4fPrUPY3Vlber+oLapewAiEA1RYt3VNAo7XKoVahjxADl47pK7WFBbkewI88Go9TUCM="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.0-alpha.7_1545380857315_0.17127457913871025"},"_hasShrinkwrap":false},"1.0.1":{"name":"react-modelx","version":"1.0.1","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react-modelx","react-model","react","model","state"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"69b6b0a8cf4a966ab493b259043563d73455902d","_id":"react-modelx@1.0.1","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-HAyO3Qqb7FSy/s3kcqHtjQi84IPItxM3OobTa6udTF2VG1wD3Mc/LfLRBZ63+r6expeXvrhoZXrR0SfSDvazMQ==","shasum":"d38c92a2843381d1a10a49ebbc9b4c61146efe25","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.1.tgz","fileCount":18,"unpackedSize":34675,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcIzZLCRA9TVsSAnZWagAADlAP/ibVStugr39Gl5DU3a4b\nb87eACDTALkh4p6SvQukJDCTdXuJW5/UCivZURjv9Y52/xR+So59d0oYqNSb\nffsebUiYOINBNOngWN2lM/0TNJvqk1w7sChEk6MLAgEa72vm+jCMWOAGeW37\n/IeS8PTXmF96B9ZSoPTgFDlPXxBk4vGCypMyj0Eunxtay5qoDxF8lM7YvveV\nNhDejDSAYHhKHjK8IWEtL4lLnz1FnFam0g83FUiQPJOZYIFYUk9BBFNfYW+O\ntDHVeso42hm2SXtP/E1LRIWaDLydLuGTF6cSM6/w+x/106Ypq7QR4MlujLtw\nltwdauyjvy78KtbKjL7KbIpOSnKEUgDAquSaH5Y0dsLYwUJreyr4OHd9X/tF\nVKo+3w8Hq8Z+Lo/YzobEhQpxlsbW8bQzRtAeaZcAIfq0TW4mt47gtLxuqlkF\nEuj9McIKF2E2OmWp5XU/v3T0c/vRDAruOLr5QTt9y7Eah2c8V1CyyqOPSHKj\nNzSW7rHruRHvJahfYAQx7xcHukTXL5ekXV5O4stTi+Jmc4BEvw6badF33qsr\naIqW0/ECSQSHaWu8pvL1g19s8iGXi19R8K9p3b47YMnIeHPZL0oubLBFg2Gu\nK+0gjNE5o4i0SH7xvKfr68P/ytScMhwAy4FmaqpGwyyiLs+Cs6pBA9IoQNhM\nr3da\r\n=Xs93\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIExXTTwPzzoUvEbzgEF760k3/CTeJml0M9Ygv65sWdCnAiEA8w2Z/uAMojwx6AXQJpLwpMJmu+RmNczE8UrDPDzwfpI="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.1_1545811530548_0.029401967198070977"},"_hasShrinkwrap":false},"1.0.2":{"name":"react-modelx","version":"1.0.2","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react-modelx","react-model","react","model","state"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"69b6b0a8cf4a966ab493b259043563d73455902d","_id":"react-modelx@1.0.2","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-nsy8A+x5XAJ0rJtgSwmFmQYlCDaI96otTlSrhFkbNdNrOkExXVh58ShSFXbYijQaSEWIduTDNG/bXBj6BBeZRA==","shasum":"b5b720fd6126627603316f7fb9cf10c9b8e53892","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.2.tgz","fileCount":18,"unpackedSize":34739,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcIz4OCRA9TVsSAnZWagAAsgIP/A2hPr2d8YJQPek3LCPP\nF70bTVBBJneWt+CntD3v+AX0VE4ofT2+tQYnbmuQ9QHdTccH5x1gi/9bWrus\nYeCm3Pb2mB/cvsJCrYPCWzTS2gJrvO0YvbtDgh4IFh4oCjljEOK0dEDyRQkc\nmdPtzksj6bNfMuZ2V1kLWp8ULLYaQQcIQjSomiIMJnv/VGLm4Cdzg0YZZ2gs\n6y8z6mUkceYLUr31DnYuhwqL+jiqBBPO7M/0Lheu6OEeNDjPrP7avyuFDrSx\nBIU/py9F+MHabgwYbwKtBJtxzms6ATQfE2dY4ADo3/AbHT6lHrr6z/1FCs+a\nzpMs6KZkQWyRMcSV6bCX9mDtf+nDc2ipc/vU0R8FF8nBVurciIhiTogFAsrD\nuwqPIoSfdxXIdlu4J96QP24nMp6p4xMCDgVSWUglhYpKvu2Gz+oOhOS4Achs\ncyFysnt0Ll3fbh0tggpAdbhF9biHubgjDjmF+bObYUnUNFw/wAMf6w8nbOgb\nmWirlQ9c5Peo6uBer34mSGgUtmsTUNMmnxVEEAvuonNFo/jdn3mqpEFK6Ujn\nHjfyynkxJHp2W0CGKt01PhGNWPWl2LhUiZErXHYLhpyah/ENVbw2AKsHWX2a\nt3ISo89D0n2vKusX6EMkI+LgYdGJdoeS0KC7kKEBsF9iCmCh0m+K+c9eZy11\neuOq\r\n=Z9ky\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBDGihYTg31M5lUbPXMFGkp86uHO04FNy7yviWy847bfAiEAy6xe3ycxnoTUntes/vMb3fxb004+RCckthFlhfyJcfY="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.2_1545813517421_0.5494538138843987"},"_hasShrinkwrap":false},"1.0.3":{"name":"react-modelx","version":"1.0.3","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react-modelx","react-model","react","model","state"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"69b6b0a8cf4a966ab493b259043563d73455902d","_id":"react-modelx@1.0.3","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-bvoDd1r0z6E6AX1Qvuu8cmINLUA51HcY4jNG5UwqcjY88TOsxVoFZSoXcPRwIBjuR8JbdSPkn1dssZWfJXvVGw==","shasum":"c4912be21124b550a7d292807ca3a28ef925a469","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.3.tgz","fileCount":18,"unpackedSize":34984,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcI0DRCRA9TVsSAnZWagAAgp4P/1RWTHbytNUnBwg1TgH9\nmvkShnyYTxs/QG7cDkV9WHzi0QdwUanqUV/01h/hHnm+JC7CxuAnBtSJqMPO\nYgEn8jPWivB4fyBBC+1zI+CVVbcp75qQdHKfJtV+RABXYdplPx8yQnJ/lmGs\nd/4L276hJk6pHLOJJQlElJOJxUf85bTBWxklaDTYhqpNyNbvSgpZAphWEzcs\nv8zUgGjj0FNgqS2vxvEFShCme5fz7VqpRonT4O5kz3xaYvdhBJm3uF029tKE\nZOofyWwDWTDj1MeUzUF3vJGuWUEY8zMgpuiTbBwaO0B3bwGQg6qmv3cZE35w\nAMUxwTqsE9HSrC1CMcP852ndCbArhQ5Vq/LP6A5nVlyaI8SxVL7BCozsEzC5\n5w1rnKmsHi0t4ne6n92pi6nklwaqb7ScFD9rDHIevAZDN3tASE5cCC/l6RTQ\nqqkLbc1QHgXBNB8NGXJQyJAWBe4op5/jC140+S5TrHA63xYMm5hH2ungYBOc\ney1qNgWbdfk6Z/xIUrRg0BJp7P/3W6elRTK4097tk9tOjFh1vHxqrMvVeTHb\naUaGkAzUq2IGO84Bk+yPsl9meoosN9lo2yPK6sGwIQVbdQ/6RFyeb/wAIBoy\nBaKnbAn15rKyUI41vIt0MH4R1vIsEYsaYgE53Gt72EOATiYxK72X7Voan/wV\nDfeK\r\n=oTOT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGz0K3qi3S1/I1tYRgxT26Jo/EDrsvxtrXUuQk3WQDG/AiEAyB3/AavdASaO74TaV00Hv6++jV1A2TVuC33Ldfpy6Ts="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.3_1545814224326_0.6319582386187312"},"_hasShrinkwrap":false},"1.0.4":{"name":"react-modelx","version":"1.0.4","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"765c91a9afe963093bac1d02a0b3876e57c51753","_id":"react-modelx@1.0.4","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-jHUfm8sL81SfHTAJuF4spHOEqfNcwyck1opIjN9ndnJlgrdTecydzyIWtQkMdH3sCXMBI99KO+nXsR9QFLBpVw==","shasum":"d60a32db22fcd30e6431eabf2e064e7ae005265b","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.4.tgz","fileCount":8,"unpackedSize":25539,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcJKOhCRA9TVsSAnZWagAAqM4P/iGNzU2ImzdudpX+mB77\nGwXD7mztzPGKQHKALFHCJhQue1L4L0HwCNkFNGOER+N5IGhD3kbvJM84zTNv\ncXLExPlrEZHiveapu9HsnMiIq3+pZplRoqEWEBF8kZIuOfWBzz8g6GLmQPd8\ns8mncPulFv5XpiVlLkU5eODjSqr7O6KRq9chIrqynlFhHH0fzcGiv0nv80td\ncsEgqJl63NHvMw6TBDzOzT2m86YLnssd9F5yYU1V2maEwD3uNXjqKucsCRAX\nPmSr59ivZ3V9qEhyb653DmJHlUNunJxNbUiY2r5dmH5KqXFbFqJ4gRkSWR6e\npcKsKp713aua0mKMCyzkksc/xE8c/jDa78kMEzWpvnwfD+QaaST4bIya91w/\njSwnXN6AWOrL5RWG6x2n/1CiFgOzeXaGcLwQ2lQRaMcfHw3T8cJP85qDreq8\nxdVTzGBLcCJGP34HabwCYjGLPDyaQu33qo+P0oKmZ5IWij4l4WFahHqOCcJA\nJyZLTSjifI01+HEEUPbBDbeVhgbPOb5YnCGNKRGQ27XfPuvbALOgeR2Fhka7\nfGg+2lrq7TNtRjrUIsM8Pf8KZLEPMSaeRPR3TEnly/LeFgH9b6lWa2ozPNdq\nLCivEszWThavPEI6IdWxNhosPM/z2OEPQvvOJnxnF6QYwKZY3YCu+k9xlcwK\n8bmL\r\n=kjK0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAv78yXD/1Ktq4nt+JL8h0dmXoDX9CdLwOa/dj/aPhKEAiBm0DFkKHe17KE+FUaVYCasSJCbhDa58MUixf8b+78DPA=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.4_1545905057145_0.4984000865939324"},"_hasShrinkwrap":false},"1.0.5":{"name":"react-modelx","version":"1.0.5","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2"},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"566de5584bbb760c8e5c904705ce4898da5e50b7","_id":"react-modelx@1.0.5","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-JEhNug+Jc5m7iSzojE9zPEx90gVjktPDb/ahnoriPWBLePFVTQaL2wJWIj6D5BN42KElI7tM90o304R8+Mxncg==","shasum":"7cf7c108cfd417a2310fbde21ebb2611664e39d2","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.5.tgz","fileCount":8,"unpackedSize":27076,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcJke9CRA9TVsSAnZWagAAtT8QAKMqC6OIIgX/RxPo3l/t\nXZ/DO71DqR91esxrVzrCOE8TiOjskFgSRHuYArRgG6v6GUhxvrOEE7ruvMEC\nOHL8zTpBR4HwezcR76m3IjaQ6Up7zZBzmi4xRMnQnvPh1PoEnVQPjwwKa9I+\nsFA9gv2rkLcV0knxSC9zTXykyj3jfLT0TGdImXi1+MUkU4HDD2aA26PKcF2T\nDyEr1aae5ng9Zr9sXhBwsLzx9StD6EZlH0OyLCti+RFy4bGjobATzM0wQZdg\nE6r9NBKGYnWUn6Ew6AuFZnfUP98KQM9daWC7Wo4k9HuEbyLTT6Wuwk082NOX\nwWjjhqt0vZMz2z/xmhqAgn4A8GUssNxXSkEL+0ruRTgDo5cEUApMs2sCGx51\nH4Kr+DM62gkxY6ia1j/a74uPRjNH0l0Wyz+mJqTKGB4EaUVnbU6j4lqd1GnU\nLv+bZe9jrWI/sn/tbMmK9DpsDMSC21JB81qPNg/s48EWvPF9koPW7cdpHWJy\nFyK0M7gv7JKcI5Mk3S1I+IOREgEAWD2ITaGU6hTQpTNayaSJyzh8tmEHCEgZ\nRGs+kcdEUEByBMp6Qz4vgUfvFebIX1oBOP54zsCqppwdpC3D17eIPPoMJNKU\n9R+l1B+GZjRmDyq/8L0KWByo5JD9T20MmznWVj70SfUIpnBFW8rZvqlgjqpJ\n9LJw\r\n=qxg+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD6x2m5NmER0fSjyxW10eow6gnpQ0bKfNeJeIRsayS67wIhAKZuO+Y7wlNMWc3FujmLnwe23LKlx2ZpD404Ml7sLrsZ"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.5_1546012604895_0.18105605414578152"},"_hasShrinkwrap":false},"1.0.6":{"name":"react-modelx","version":"1.0.6","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2"},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"566de5584bbb760c8e5c904705ce4898da5e50b7","_id":"react-modelx@1.0.6","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-DA7iL7R3/KdJpQTYPe0HVi0Cpgad/yMSuQjF5hybINCknUDB1W8aGng66+6UdXlpMZRLygcTC/Un2gUlhTNpRg==","shasum":"1d918c6f4f7a67143da401fcc8edaa6eb364e683","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.6.tgz","fileCount":8,"unpackedSize":27080,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcJktPCRA9TVsSAnZWagAAzdUP/jpT+vpOe1yKb1NrbQlm\n67hrrgZ+vSNGE0U2ebUbKpbu3R6qxiSgsUpCb2Atrq8k9McNL9Yf8F2sbatr\nJf/WY1iD6JZoDJPTu9iiC30W+92rWCKglk7BaMLKv1eVfYFuhJ01799Bj8Wl\nrvVhavtQfRzN9lC/7HYc90aI6YL2N5JDYtPwt+wWDujjoPPWUC6a60cd2J+P\nmTLmTVub4FR3lA79OqW8cz636dU5JgspWaDeLWmVns5JfNdDS3v2uP7eoPAQ\no0jS/q+AM3jtk6FHKtXsyZHEHYCv9eWTZJRRZoYB/iP2il0BPI3jIzYglg8J\nC83wGh+Mq+nTGkvtBRhrNHBPiAju3ZK1hhTqUAmi4WePHCxscC9FN2yenRZn\nBZ9IuHrh7OawijAzvOdWTZgnJhorsu2t9jsOX/r8IcibzJi4ukMbpDZWh9vd\np9nFpU6IdcbHA40SsgZ6BLoNsdjZw2/SCRLlCeem3topOgxCH7d38nl+L6Vg\nBRb49LjIeQBM8cnthTz6VPHJEfsOBHWR+uDS6Bz+yPSY7j54X+PdmXCDSD3x\n6OG49EO3dS0m8NFlz3blSMQu5Zh9qqNV680HUf7YIP88kGb3XSsFkA3uHBra\nqiLrnpz4g+H3TBdVBDql6gYBMPUfbL8o6TTotBvwjdjWN6XJxOvOWMYEH0OL\nEgFS\r\n=2AOv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHZxRnjH4+aJRgoymQ/woAZmK6QXh55HZlG2oI4Ln719AiBNYZskT7QCkwD8FepHHsyQC0gwt8ZtMbIpr+/I89EcPw=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.6_1546013518645_0.1965778416992523"},"_hasShrinkwrap":false},"1.0.7":{"name":"react-modelx","version":"1.0.7","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2"},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"b86680726767cc96274caa166c6dcc54f08d201c","_id":"react-modelx@1.0.7","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-81f8NA+OFwCfHyeudpwyNQsPg59TqXLg07d2ke7h7UGmMCirHJZgzqItGEztdg3I12mJESkjOIOA9zT8NHe75g==","shasum":"e1b7d7872a5056e94cda9fb013b3b7360e2d235d","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.0.7.tgz","fileCount":8,"unpackedSize":27486,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcJ0+rCRA9TVsSAnZWagAAaqIQAIdPr7IbdP8Xg95wlWb2\nLo/abCQJII5U8sRfvkgqUQv1cHL3aiIoC4yuZ64TvWGjz5a86JjdQLpgE9CG\niEOOiy9nJjmA+n5OFj5aNqogC6zqzxFMLrdI/mE/eSEr+11uJNoEkXjhXn1T\npSISrucE5Tw7TBt7MkD9DO9pJM1FA6g6lIobLbD1JCQNfkD8zGY8jyRx8lar\nKOICc8R68w4JxxxKUNCVWIN/TurCSEwjAW+ejCTVWNj6CHVg9eMnY5vJpoxw\nlJXd7DAZ8LmrwMzu1YQdg5V0HA0Wi0lEcWd9c7pUveJv7bg1A90otydLjxH2\nEuHpL5NO0kaWleb8VkNoE+W09WKYwaYDweuRoWvoSj3jbPLJT+xmwtnPvLrA\njmZP8EHWgj6v+4/BHnvS0mAOr0RecoTvJcwnmDhi1Idr/NBpPnG4ZmPs9Rtz\nl9JXiaa703RL2lQ9YijCDgsT4oFjB/nNJWM69DIBn50iXH07jH3HENHMR8QA\nnvLqUDfwWHE+7m2NhlL3w5VdofSURp5c5XSO4ekvAokO16aQ9uUC4TdcjYvl\ndYmEGNxcwZwMVRNnpctzkBRVwVA+iPsLS9kxED+7kVuy21s3+i9ymEkdG91i\n+Ws/icVSzoG+YIaMqZK1TUZde2ydLNRNr1zTjZ/6fEDl8vclGe/8KuXsIKmc\ncVel\r\n=hbdV\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDF8bGSll6uI7dIKd4/BICENWGW0wHrmbQS1vDJgwzqkQIhAI5aDSPbx0EGOmLTquXKL/sde/85zgMVX6oX9SWd8spn"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.0.7_1546080170641_0.4410420353757978"},"_hasShrinkwrap":false},"1.1.0":{"name":"react-modelx","version":"1.1.0","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2"},"devDependencies":{"@types/react":"^16.7.11","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"5dcd2d165ccb42ddc2f402ab5b5f838f5aadf30f","_id":"react-modelx@1.1.0","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-1aEJexIsuhmSemXeantauQSZWkH0kAogvzj2E/M6BOzPVP6c3M1+JQc/ykHA3Gbjz62kGWPqL4/DDbww6WtVhg==","shasum":"466d92b45a2e3620a5c292f49d3f3f0b73721cf5","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.1.0.tgz","fileCount":8,"unpackedSize":27104,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcKiauCRA9TVsSAnZWagAAhdEQAJ1c5ZNvAALsTAEtbxU2\nQZaDr0T4748pbJLI+lTZ0v10JYQ+9NMKe3QRSqdxwxV/bh/WkiW/suylEs+7\nh50sWiNlBXNN0acY9hSLCXt1ZmiiSvhO2Y3Z+9iZop4KREp66NM5jRS/hfBq\nhxIDsalVK666iirpcj6tq4XRF8anj1RtmZt8KgF85pfNX4qrhwCmM1/eikom\nVGok/8rITaKvQuHAUqiQznub9BakIZiSu8OSBmHxiWuSqe3dOiVJkLLgu0l6\np6EV3H3tbI32AQiRZ+fn5un1UpstMEEH2RTRouYiMg7e7uELurUZ40odEpNB\n/BjdvBaxifWZhR+VJlsfJNJWsXTfzzLsg9hrffsZxbEmJzyGAVUjncgS519i\n6kBZJBZac+H4//CCHM+lZcX58raKcmLdmN9KrxV2XONo7lw6Ay4h5eBQVpl0\nzOF8OFyMzX6AfdfQIkwKoQ4xszJCfBwI1XB3xXitEXviXam74m/ZMxadQBaz\nUMeCwols4sM/3raZtQosyvHtAMABLRCODrMB7ETMFgCCHyAKV7f0EHftxZ/e\nyEkrRUQyjJHIlWN+UGce/FcjrywEXlCdvQuvBG3kCorAuB2E+oF+cluDk4dh\nyKXZYgazgbMzO9xojZacEaxBCIdQHRdu2ph8XU7qXuSm9N3w9QnK9/BNvc9S\ntYQB\r\n=O+gO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDGVDLONH8PPfwAtORHzk7no3NKIGxgXbkflX0XW4at7AiEAu5ODIg3/hFqKTVwSL7LtSOMBKKQQcktCowZ0pYx+Ksw="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.1.0_1546266285785_0.5582320627473818"},"_hasShrinkwrap":false},"1.1.1":{"name":"react-modelx","version":"1.1.1","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2"},"devDependencies":{"@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"7188890ee5a348f3451b3515eee661548cb48cdc","_id":"react-modelx@1.1.1","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-5ytrhrDD0h4xOL9S2zLNNk+lLuzMOJMMWHjbDnn7YNuzUuNK9PcI/1COhjWcP/+PsxQcyExfMpmaDeu/yW7SSQ==","shasum":"d13a6ceb173892a284aadf23d134b3eae8b8ae40","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.1.1.tgz","fileCount":9,"unpackedSize":30858,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcLdhWCRA9TVsSAnZWagAABTMP/0roumH0ZDK12rSw+/rS\nNucgyGr3VrnVQ1oD/+YYjN53cNgx3LJAscgqMZgJK3KaWR3S5PwFTCQXpjjh\nuSIDKuP0wBvbEYQDzZUCPn2hr4zlaJjtXdZ+Uywmvw/SVxbfCcinSiN9E0lx\neXRyxQq7QONyxKlcoQJ64RLk3+x9g0pvX0JP8VqVYHEfHhJXDvYZADYvXTRR\nIOAqocgkfwSEVa+0VMHLqDZEeLiucWV9+b4dVyPf/Ccq6TpAfEyWjnMI5qyr\n2pOdSVoe5dXBv5KO8iedS3tfg28+EoQVIXtSPWTYuKha0S9kVlpBj1DU17Oa\n0xlTHrDCyvn8QUxPjQMjxC6UCdBDvIOrdOfLpQgBglbSw5nrtfJO3McoH6TX\nbkk3TFxgTjJQ9aE/iDriUrQw5/86Ylb93YmMJxjGr3VvWW5ylXHOydrp3smI\n0dRRxCAuFQSkCyWMUoKhYaa1upE5zj9kY12NcITwzF2AJOFAHLEolT9gqKLp\naKjfKfwAqXBoUaGoyGC3m2UJbIoxydZ3cUTvLishPB1ZAzmwX/ztM3pUwKpr\ngEDNwohOpKTn47FEZVJ985WOyWH3NsqLB9JATH+UTNWjyjSq+o5H/eity/Up\nVHnQOBykwZwfH/6+YpxrqdWucHiUvl73BWCvnAL+FUsplFW64MhaXB2PgVZF\n/1bZ\r\n=gaT3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBG8nuITlSKeXKEJUYNUAPic+lwgpMSfn1WysLj5iWNLAiEA8SxAgDdtkKuujKlX2oXBfjBzhU+FoUClHqITy2C/p70="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.1.1_1546508373548_0.9529881803740707"},"_hasShrinkwrap":false},"1.1.2":{"name":"react-modelx","version":"1.1.2","description":"The State management library for React","main":"./dist/index","module":"./dist/index","types":"./src/index","scripts":{"build":"tsc src/index.tsx"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2"},"devDependencies":{"@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"e59e1ef632398f871ee526ce3e6074435f7d7a4b","_id":"react-modelx@1.1.2","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-U8dZUJbgG6fZgmwjwQxt56R756cBiTbuLHOIEKY8HZ3+C8bUo9CvZAn4p4iCYjYnWpg0ZLvE9iP/uThYWHyKYw==","shasum":"b7af10cb39ba9d324d6c5db63e5809d61a0c53f5","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.1.2.tgz","fileCount":9,"unpackedSize":31906,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcLeBGCRA9TVsSAnZWagAAb3YP/3pwAAW3GRVHNZ18FwYe\n0xHYwc1Zr79LTFxjUjC3A0lq+ADtXkfEV+68+GItS2qlLPTl2L2MZY4T1fYG\ngEAXxRt3f2A0CPpXQsDJ//Im0iyBQSt5Sm/TdiC9RSxuMlYPuDfbVzkvv6up\n1U+ed35k9HJb6n7VgYcv6ClE+TuO2BiMdpaqBCmxqXtrAwVodQKBAlQgo6IW\nGyQQGWObxdoPGkf17thGgYWLCOAgVt+qlm0Wn1/UZFtTy/Sur8h1UuSzLqB3\nQ/nRYdobbi//eacyyghkoeV7UqNGEffXIzBMV+WCgfUrNzHRBuGtD2+g21ZG\nwoJ80vAI0ou9Q3IvMqe1mOxVkXSGuWGt6DS+P4ZjseroFnov32nuSn9ILyv7\nhelhWdbI8cDp2R/YHg4obVyHdSij0iUsA4KjbWBvvKQygIIbIpKvWT3uz9Oy\nCr7Ijy2i0S81lo1U7BaCO+fKSaweRJZHz0izdeQ2ADgYjLjr+3HksR+Pm2jt\nZ0wVj217jU4pQTTm9cREC5XP7aIZavnsEtpnh3hpQf1wqn4gmBk8LE66H7Kx\nWMtqSYy54EdgYbMGHE09s4CZvQVdeCnLpkT2VuSG86Ry6o4+qoFcEE1bH9oj\nNRE8MqDfghG5CoMtMkSPVJ3Bdyb11Upovhbq/GZ5CKRRFnexBMmI648Xy1gM\n8rFS\r\n=527F\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC+ioDOUNuml+ERGfgtOlBZ5LBV9tSASB274tIvmXGMhwIhAJYKzU3k3prCdQMzNil2r+vGL7HMxbFjQ1nRxjK6YNos"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.1.2_1546510405566_0.5561720417589437"},"_hasShrinkwrap":false},"1.1.3-unstable":{"name":"react-modelx","version":"1.1.3-unstable","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2"},"devDependencies":{"@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","dependencies":{"@types/node":"^10.12.18"},"readme":"# react-modelx &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-modelx.svg?style=flat)](https://www.npmjs.com/package/react-modelx) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/index.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/index.js) [![install size](https://packagephobia.now.sh/badge?p=react-modelx)](https://packagephobia.now.sh/result?p=react-modelx) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n## Quick Start\n\n[Next.js + react-modelx work around](https://github.com/byte-fe/react-modelx-experiment)\n\ninstall package\n\n```\nnpm install react-modelx\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n```typescript\nimport { Model } from 'react-modelx'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { useStore } = Model(models)\n```\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```javascript\nimport React from 'react'\nimport { useStore } from './index'\n\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\ntype ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\ntype ConsumerType = { actions: ConsumerActionsType; state: StateType }\ntype ActionType = ConsumerActionsType\n\nexport { ConsumerType, StateType, ActionType }\n```\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n## Other Concept required by Class Component ( Not First Class, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-modelx'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n","readmeFilename":"README.md","gitHead":"69750e50462d15da71a7b40efd1099ee9c0094de","_id":"react-modelx@1.1.3-unstable","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-NzQUuZ+Yp1iZGRQoKx0BWBIRdNKH+mQ4lPxh2lM0HnQdLEhOptgwKprl8rPiTF4D9mmiKAY+YqLa0RWsu20mJA==","shasum":"6973799660cda6c2ac8b75d7b06f84232ebc3317","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.1.3-unstable.tgz","fileCount":11,"unpackedSize":30512,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcLwM3CRA9TVsSAnZWagAAKUoP/jqYt39mktJWBglGyDrp\ntbXOtX707pVE6UElDVHNi4MwRZPNMM2ExGji2tk0H8LxPSGYIdznPhf0TZoR\nFW5S1OsF541NgTXRvCUXKDRmrZZnttp76wGS6PlzlWMl6T+GKTytHrNtxpMk\nZN3IveuvW4D5qdXxMsbEVQ+VUwTt2ctm5zlyTMNRxV5jkFZ+TMyYk5u0onnE\nw/esZmlqkPsLqe7zw9m30CflH9FcCJ6oqSDzpYtKmEi6qkhcPRFN0yHkL5SK\ndZKxfPRBo+G2Xh3hprDJ8PtZ0elYX16ug41SQcFH43jibvEdgVmlL2T6Kfl0\nEfoooQPlWG12cbr/UaV67HQf7zIZDtqYgBGpEYfa2ihE9eoE1+lRd+/hTchd\n+Hs+t0Pz78u1txepa82Ks+afPacSL4sTYLvYIzqztNlfL8RTuICUp/f9QXeJ\nXPRUSiRBjBm3dq4sPCTLs4POpo1kapa6sLkcm4l/0xs8eIIEyr6+z1rRmV7W\nf+2Y5dDORCTC3jmiAPFZQfoV7aAeIUU8oOnn5CiKjzT8Ql82yDqD4kbvErzj\nvBbnQWG8Wzz8EkX5241nZTU6Gh1FdfRbkpYCUxEfDrEmrHZK8ro4vFgQRab9\nlUtIeDY93cXjHBzBm01hXcNvl3Cw5p5a3P/+eRIcoN8Z2+TFdrN/YpGQNTZw\njItw\r\n=Voya\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDIkfK4cVOV3Nap1qVhqb0mvJGIHNvmJnFG8cslhVhFOgIgeNoKSpgg5Igq50jwR//+ZrMjTJvSEGvsc70VkDnKT3o="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.1.3-unstable_1546584886802_0.21314013023338263"},"_hasShrinkwrap":false},"1.1.3":{"name":"react-modelx","version":"1.1.3","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"cc54648d95797337b4a34230630f2b5348be553d","_id":"react-modelx@1.1.3","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-aL/wXMIxvtiM4PnFAdCfbRsZ+Adxcy+TbQi4ZPt2DTTamIpl3fDVxevKaaadrsZ55Ic41iSo2KQsisG6sMl2XA==","shasum":"6d75615f6545b0b00c058b2f05d780bd1ee38bfe","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.1.3.tgz","fileCount":11,"unpackedSize":30479,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcLwbLCRA9TVsSAnZWagAAk14QAJA5XmnTsaIT553PQoev\ng+LlrqlnodyfRwb0UeUW9RqodqhnJRGPdIPX4/ndKELJDVlnInxoTC63zpyU\n2UWICIHP2tO7IrzdcuTLwaRgVy+Y1WvfSf+q3GrS6H8kq9EeUyNWbOOGK0yf\nOzsAtolM0HeKmaSeZYqbA6O1wjIe7l5JuiONPFQkHEVTl4pbTu56QhcQxo8J\nnOBsNJJgPEXLZf02Mif5sSYuYji27XA8BeYt/K3huzjzZ+aTkQd366Z5paY3\n7N9+fmNhia1xCxkbtNbaiMgVB4yI7j3vaTui8CB0hTBlJRH+qzDs8QrUnziJ\nm2cJTApxwo6G7UUq+Wnh4qaNFJKQ5mgBqCQkQD1/SxKsbAM+rOiFubGXNcla\nPEzAoBiPMVi1lOKPt3Bs7qHtUHcwfiO6bhkwSEo0XrIvsqTPNxJ4tT4+OBIf\nbudxzexbdLCZxgoH0MaS/2OUzQlOHR0hftgcUAPW1f1XZV4RhSMjM+1Ts2RY\nLsr0QPI/+dCyD0YhiJGG9xSJRyVr1xBvuVRsHKWlU+dMn3Pz0ftZEKFsLx5B\nI27zAW6OYZ2kf10CnwGW7/noGMIDytaLMVy4oPHeU4gPgCZMFJz4v/bvlcbL\nGMSVS6s7licrL27DdBpdKWOJ9UYEghRAp1YGEKzqzAR+Ezco9sLBy1ZdpDMU\nW/5T\r\n=HZwa\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDLzDOBYb+v+NRNbu/bZsOincgjPovJbHyzeRUHVxgDWAiEA3tmfurlhfpzO0/xwDA1QNye8JBzo1o6tRZ/SJcojOGs="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.1.3_1546585803052_0.15669615968875994"},"_hasShrinkwrap":false},"1.1.4-unstable":{"name":"react-modelx","version":"1.1.4-unstable","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","readme":"# react-modelx &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-modelx.svg?style=flat)](https://www.npmjs.com/package/react-modelx) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js) [![install size](https://packagephobia.now.sh/badge?p=react-modelx)](https://packagephobia.now.sh/result?p=react-modelx) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n## Quick Start\n\n[Next.js + react-modelx work around](https://github.com/byte-fe/react-modelx-experiment)\n\ninstall package\n\n```\nnpm install react-modelx\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n```typescript\nimport { Model } from 'react-modelx'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { useStore, getState } = Model(models)\n```\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```javascript\nimport React from 'react'\nimport { useStore } from './index'\n\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You need these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from './index'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n## Other Concept required by Class Component ( Not First Class, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-modelx'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n","readmeFilename":"README.md","gitHead":"b59a45e8320ecad52457fb10a85abceef38d7d73","_id":"react-modelx@1.1.4-unstable","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-1uPxDdtwFqpRAea5tGyKSTXdlCYh+7L/mdN5lLA/5JnpwRJAK7hogrNOrTbNe8JwdE8/Q1EwZPKmBdjq8Jc6Ww==","shasum":"74349526d7e2d82f6c2590662cd9ee8d54c5b783","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.1.4-unstable.tgz","fileCount":11,"unpackedSize":30851,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcNrWqCRA9TVsSAnZWagAAZsgP/R899/tmUp/5OugY5F2S\nXSWj2SQlQ31289yiHXOWkLje1Dkkh/ousm/NMj4ExzpV1PpK6QCGJN/VBjzI\nu6vQ8QIMQNhl6QR5Gk5r7Up2i4D9sv/p9d+VkJP8NLV33uZHYZTJUOh3W8Lv\njw61SoNPkTU0qeFBWQv3SXYgT/hWP33WjZG/m11NVet/KZH0zBUPma95acJp\n1LJhxEVvQJ/dVdcOeER78S4CnFqX4fPa/OsbbDb/8e7XlfPZoOzuIokVluSw\na/wElNS2smrS7Ps3gZqHIshS2b/ZC4os5Uo89gjTo0S4vWAD/s/4WdEt/SBA\ndQUvqO5o6Td2MIHFrIPR2RO45zfre9iSYvPg25WaPQXu7n2FrJIPfJ8+gWfp\ncnyRsJefFQzLFXBf5gReHJmd4zi6SD+ki/tvUIY1pPwiLuy/eD8j2JRYhsn8\nUT3JGFET+NhsalQMj9kmvQ05Pio8X614Zt7ddH4iZxj7j/PlktE8/iqeAzqp\nFv+CtVQJ14twQBhkA0qZ4bUK4MQmmuXL6EmLFN2LErtFykaTeMKQflJ+hBB8\n8IULquXYhFbIc0h7guihEUGAsDjH+wO9dHQcbS3UIBhvAg5ILCPqGGUtIlPf\nTmQFH6WEwAGQvGXBW/3Z53DaneuGliSljHDZt0TEHCh6xgFZgCXrzXuLtdhz\nbhPt\r\n=YuN2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHfNwK8/cXqFKSDMFf0OXlaVRPl3gQef2LgiAwZbjg4jAiBuRJfrG2/n+Fx+a4ih09tiAwjwdRrXmLSjhy0LnM7Glg=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.1.4-unstable_1547089322112_0.5752835044115807"},"_hasShrinkwrap":false},"1.1.4":{"name":"react-modelx","version":"1.1.4","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.7.0-alpha.2","react-dom":"^16.7.0-alpha.2"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"b59a45e8320ecad52457fb10a85abceef38d7d73","_id":"react-modelx@1.1.4","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-pqyFeNfYHM/s/brblOVTkdxpjc9dWB+KdFkAqj+1gYbvs0o2U4YQuKEIZ67hWeyQCTwkY7cl3MVoo80Aq+8AXg==","shasum":"42fe699db44ed6b70997997e32371158be3c6e78","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.1.4.tgz","fileCount":11,"unpackedSize":30842,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcNraHCRA9TVsSAnZWagAAw1IP/RDO/Y3M3DvtJruGxsX2\nMRAhfJqao6R9aI2nmNUdWNzBMMNVvffMZvvxT38pBXXtiWIvtUQvkkuTzfCh\nO86K7ZQZFhhrXEX1/lAs2BmBXlVuzKHxgUichRyDmRqb4M0un/owNrJAdpM7\niDFj76EweGj/kjBFfCzKb4FO5luuBC+ib1GXrtdqDxOIbyvrR7cxmp4mwpWn\nXEtUaKE547EVW0RfD0Dlzog00mug4f+U0CWHq/htf+EGS+l58T/kbGF6/dLs\nHZn+rDfVAfBIw8D7NRQKjn0wIJ27xiC/40V3E/owLPBIaKisAy9AB3BYO7Uh\n98dAtsQ6iY2ePQmEOkc7KkHsVYP2NYl1Anz/zc4/V+RIsbbxtLYPxJMQ7ZmW\nm9XvRn6zWP06uOGT8y2ULC1Qoyv0DEP5AWAuNzMLLRbaUZP2MALk3awelNOk\ntsg+5GOEaZ22hbCDc/KXlsbMuaZH4f8zfhvXgOH+vp2dRYNUqNwD6VLfli9M\nENLJryRPUMc7X2NLBmfzKVknoBQI/gkJ+poydK36DvT3ZgrKifDpgqMNdks0\nSAInF30KnwdwOn1nKykSETQB/chtUncsDIJ37jtd0kRkyvO2jiNBlXHzDZGF\nrxfI9i6ffJY2eJC4T+L4CsctzKDNtZUwS+1IF+Ye6PFAgFvfTXgAhIPIZMac\nXQhD\r\n=ayzM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCvrkEPn/2C6IEbnkxPs2cx9AmpVMuTvB7VXUcl4hTCIQIhAOz+MqlKDtYtUEBaymiYpewcbtfnc4O215gQQb2I9eFa"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.1.4_1547089543128_0.3000246295657585"},"_hasShrinkwrap":false},"1.1.5-unstable.0":{"name":"react-modelx","version":"1.1.5-unstable.0","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","readme":"# react-modelx &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-modelx.svg?style=flat)](https://www.npmjs.com/package/react-modelx) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js) [![install size](https://packagephobia.now.sh/badge?p=react-modelx)](https://packagephobia.now.sh/result?p=react-modelx) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n## Quick Start\n\n[Next.js + react-modelx work around](https://github.com/byte-fe/react-modelx-experiment)\n\ninstall package\n\n```\nnpm install react-modelx\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n```typescript\nimport { Model } from 'react-modelx'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { useStore, getState } = Model(models)\n```\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```javascript\nimport React from 'react'\nimport { useStore } from './index'\n\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You need these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from './index'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n## Other Concept required by Class Component ( Not First Class, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-modelx'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n","readmeFilename":"README.md","gitHead":"b59a45e8320ecad52457fb10a85abceef38d7d73","_id":"react-modelx@1.1.5-unstable.0","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-vTGb3TJjuG/gKeyNG3QEGLeHotum5Y+lvnxTDVHnX67sFw8dFchdiyZYuPa0RTyWS/ZfgALItOB57/9HQ0aqIQ==","shasum":"ba696cc0a5badf558517f67fc87b56c519f8c2ae","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.1.5-unstable.0.tgz","fileCount":11,"unpackedSize":30853,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcNvkaCRA9TVsSAnZWagAAeUcP/imfYW4lTRCcjB5XYU03\nxpidmnmlgpvDF9X5d3SHQ4vgTkvVflD1rnwq8lIIaJfwRlXA0sqcVR2Ld9IP\n1+LTMpwqWo90FGojdTTx8YRZm05b2upwkg/Fi1N4vUOaALMOtgVDD4tSp4b3\n0PEMDyF9SOAKkPlyTBEGAv/TwvpqI3ELnl2K4ixJsKMMRH3lJLrBk+7D7O2t\nYZ3hpUH5unvBDpxVzhbfzxqvJL6MzQ9W7o+jBZr4EmNzrxnpu+OMkcmPuNdo\n+XKAzFgjfT8dOhaGtm9I4tRVgUr2oZiQkE/pk4NrkAQCbCzSh4kJWoIH4W+m\neB7WGm6TX8beM6xRm6VT6wnSG800pU6FofMN2WuhNyFHE/uy0e+BUWzczmM0\nzIMCbumCo4m6QwOSBTznrU/MLtB6bGmD4z/MMF8l+3ya6HXvc+S+kyYaZ4b3\nANYS8CrTxDKxZIQ5QQMnEeFE+emf7ffMaARiSX5cxEjmf06KAD4AkHYdibBY\nSaFKvTwgILb39EqUeopvCxHQ4koz45Zf+sAOlxHyJqfi4OUUnM4PyMj92h9s\nlvmH6C+TFlyH5FF2l/sHeT6pFQETobO4HKSOwa7SzAuJFxtFWn4ccOH2L1XN\nlOe0o1X6IcVGJpNS1QibudR7ByK72fIkaWn/l/JqNqdNQi6v3c8+Wv4Z/rO/\n8Gbt\r\n=sIql\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCRYtpVjIO0bct48yZOneTif1c5PDQy7m/ZgtD+nDQ03wIhAIj8ubPqgGreh+Mwu2tZer0j2JM238v2hH3mn3QhAy36"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.1.5-unstable.0_1547106585982_0.5168555398528754"},"_hasShrinkwrap":false},"1.2.0-alpha.0":{"name":"react-modelx","version":"1.2.0-alpha.0","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","readme":"# react-modelx &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-modelx.svg?style=flat)](https://www.npmjs.com/package/react-modelx) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js) [![install size](https://packagephobia.now.sh/badge?p=react-modelx)](https://packagephobia.now.sh/result?p=react-modelx) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n## Quick Start\n\n[Next.js + react-modelx work around](https://github.com/byte-fe/react-modelx-experiment)\n\ninstall package\n\n```\nnpm install react-modelx\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n```typescript\nimport { Model } from 'react-modelx'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { useStore, getState } = Model(models)\n```\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```javascript\nimport React from 'react'\nimport { useStore } from './index'\n\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You need these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from './index'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n### SSR with Next.js (WIP 🚧)\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async () => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\nexport const { getInitialState } = Model({ Home, Shared })\n\nconst MyApp = (props: AppProps & DefaultAppIProps & RouterProps) => {\n  const initialModel = Model({ Home, Shared }, (props as any).initialModels) // TypeScript Support will release later.\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} {...initialModel} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  context\n  const initialModels = await getInitialState()\n  return {\n    initialModels\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nexport default (props: any) => {\n  const { useStore, getState } = props // TypeScript Support will release later.\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n## Other Concept required by Class Component ( Not First Class, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-modelx'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n","readmeFilename":"README.md","gitHead":"d40fdf27da6983474c00d464c84232518053063a","_id":"react-modelx@1.2.0-alpha.0","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-6hfi8HE+JTiquCQKZVnF7krfEW5wLUGLOW2kep/LOqFwxgBKr2C/cOh0xYtb5bkGGO7JVk4Nx55W4h+0TbSaWA==","shasum":"8819c47d55d8b541d9ae2754e0914af841aad2a4","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.2.0-alpha.0.tgz","fileCount":11,"unpackedSize":34819,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcOA7nCRA9TVsSAnZWagAAXvUP/Az21NMVxC5H4wn2q0Um\nX9eydB2x/7ILh+U1LYCNt3fVshX5Eq+MJ1panyLULLi3TXq+6ob0zdxNJEVF\nYYpQf2K1lg0n+esLnzo21G4vccjcAt7MnJk1MtUqy2bYztzeoLJRLNfhYAA5\nSaklZbVH7y4l7Vpra2auTNh/tTDXwIYjulqHlvWOgbyOPcm/kNpQlqI0ABcv\nSH3Wch80yNX0efWIGkK522sCzRrA/LCwIjAOklIzOuFGOQ5/GI10JTQ2Xsv0\n97LUKrLX0STFg9lU+vDe6Nd4DzDhplEHfBCdAYyvij42nqlLOJmpZ020Fenz\nbZao3FY3gagCpl4iKHU8CTdwIGdyse4Z1Ls3oZPhvQwF8JffHbnXuFA8q83U\nkrzhaT2QX8mgUeVmCDws4pAFA0u/+X2Lu3k88BjUTT2WGXpGTYnkYt3L6fOh\nv0ZQs32Rh0P3NqzxeBDVtKMV4it7JcRW72NpfUJ2eIyx+utt5EXxbI5gLuFN\n3l4vJXoPGwHAewshyCkL2iL168jLPZ5AlfBXpX7IokXy6bifClkdOKxYYRdZ\nq4Ge/v5/K0m/K7Tcp4O4cj/I2tZ+g2rw4QA5RmbBcF2FIJf60qubaEzIbG/N\ntVjEuwgb2eJ6x2J2AZ9o0LNissMDa0/2/OMyR8cOe+UX7efH61ft3jFU2JYu\n9shJ\r\n=U0Xg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDE2cRydtXHF/Pe4QHrZQElElizLjnv37z7Ararjo4GLAIgdj42IKKuIASMewYEn16p/8kLFw6A4ohqCpCaFZUYXk4="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.2.0-alpha.0_1547177703188_0.14179798539226085"},"_hasShrinkwrap":false},"1.2.0-alpha.1":{"name":"react-modelx","version":"1.2.0-alpha.1","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","readme":"# react-modelx &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-modelx.svg?style=flat)](https://www.npmjs.com/package/react-modelx) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js) [![install size](https://packagephobia.now.sh/badge?p=react-modelx)](https://packagephobia.now.sh/result?p=react-modelx) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n## Quick Start\n\n[Next.js + react-modelx work around](https://github.com/byte-fe/react-modelx-experiment)\n\ninstall package\n\n```\nnpm install react-modelx\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n```typescript\nimport { Model } from 'react-modelx'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { useStore, getState } = Model(models)\n```\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```javascript\nimport React from 'react'\nimport { useStore } from './index'\n\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You need these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from './index'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n### SSR with Next.js (WIP 🚧)\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async () => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\nexport const { getInitialState } = Model({ Home, Shared })\n\nconst MyApp = (props: AppProps & DefaultAppIProps & RouterProps) => {\n  const initialModel = Model({ Home, Shared }, (props as any).initialModels) // TypeScript Support will release later.\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} {...initialModel} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  context\n  const initialModels = await getInitialState()\n  return {\n    initialModels\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nexport default (props: any) => {\n  const { useStore, getState } = props // TypeScript Support will release later.\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-modelx'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n","readmeFilename":"README.md","gitHead":"d40fdf27da6983474c00d464c84232518053063a","_id":"react-modelx@1.2.0-alpha.1","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-5af3JB8aAuUjg7O8VH4dUaXKJP/DK+AxL9RJKX2P4d9nMupkn1Xwlft+bl4kSCvSnERESXBTva0tbuGrcB6n4A==","shasum":"04cc24013ed7bd87d9fb7bca79c8e71558914207","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.2.0-alpha.1.tgz","fileCount":11,"unpackedSize":34840,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcOBhYCRA9TVsSAnZWagAAcLQQAKOyT+iYwKRci4U1Stfy\nUN+YjWsmn4+T/n7+NIoC+VsEhHUk7zcWMC+fHH5L2vf2iiPvFLdPU4EA0vPB\nhRwTZ/Bpg8qaEmx61A7t4rw9iuMU1AAUMvq6FYYzIgnIXhgSJ7c1UGbfDVAL\nZ884imp+tDMZyXEpdKsuwIuThQ9+kD6uxEdxeYuu5eeUWHkVdmBzj2IO427W\nfu7wMlRgViXtbezwWHm4DSi/Rmr8qBKoiw2d1rejR82E425z+0fvNoS0tjjJ\nh6h9mqDFBCi/UiTt6IA6QZJwjT8RpbYbwkSXgv6MHMF69rgU/6tM3Z/2uyjQ\ndxDHqo49H9A+2xMZ71ONHeMoUl7YHCGpZbsRGWl2nHLjs9drrUK/RdY7RWy+\nvmQqMihmlqb62AIBta13tZPbA4I7hOmbfZCYm0SQWgOrpYoOLtonujKDYx4s\nVbhdAJ1Iz8ex7N+B056MtMD3VGpb2ZyuBTP5e+SlMqo/i+H+5RMsQh8qKOHA\nxvhl0nAyUJC5JQ614b8Ex/WZQJD2F/MgtqXuZ9LigKlfR+wL2ycnSOVlOvs8\nWTU/gJEW5/b5K0a2YmN+YPNDp5eGQ2eaL0nnYlWIu0loinmOWE4LFlyXB9ok\nAk5VfjVHbkjVRc1zRrZvvz0WIb5saU4Pjgdo8fJrTGx/ltLVdbH69fnTbMN8\nnabd\r\n=lXIu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFL0gbYks8e+Dm1LYmU9xA8bXrTk4cQ7nuMQBbiNlcEeAiAKaGXdKn5la2AZpunNagjLGBAH7vxHJH2J6frq1W8cTQ=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.2.0-alpha.1_1547180119344_0.1918832336974874"},"_hasShrinkwrap":false},"1.2.0-alpha.2":{"name":"react-modelx","version":"1.2.0-alpha.2","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","readme":"# react-modelx &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-modelx.svg?style=flat)](https://www.npmjs.com/package/react-modelx) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js) [![install size](https://packagephobia.now.sh/badge?p=react-modelx)](https://packagephobia.now.sh/result?p=react-modelx) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n## Quick Start\n\n[Next.js + react-modelx work around](https://github.com/byte-fe/react-modelx-experiment)\n\ninstall package\n\n```\nnpm install react-modelx\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n```typescript\nimport { Model } from 'react-modelx'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { useStore, getState } = Model(models)\n```\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```javascript\nimport React from 'react'\nimport { useStore } from './index'\n\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You need these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from './index'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n### SSR with Next.js (WIP 🚧)\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async () => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\nexport const { getInitialState } = Model({ Home, Shared })\n\nconst MyApp = (props: AppProps & DefaultAppIProps & RouterProps) => {\n  const initialModel = Model({ Home, Shared }, (props as any).initialModels) // TypeScript Support will release later.\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} {...initialModel} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  context\n  const initialModels = await getInitialState()\n  return {\n    initialModels\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nexport default (props: any) => {\n  const { useStore, getState } = props // TypeScript Support will release later.\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-modelx'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n","readmeFilename":"README.md","gitHead":"cb4014680c14d5f9ec5cd08d56f4742493482f5c","_id":"react-modelx@1.2.0-alpha.2","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-8ohzbAYtOhbVM2RCfRdzweqCZ8jh40Kg/hA4qy9zxFFeJZVailPa+soe9S1v8plop39O9zBpI3n4v/Ql0um67w==","shasum":"9f24d92b5055abffab8107f2a241131c22879e3d","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-1.2.0-alpha.2.tgz","fileCount":11,"unpackedSize":34814,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcOBnnCRA9TVsSAnZWagAA3D8QAIxNqnErP+sdb3pZcbyz\ncmlMUhFtPIE+z0FXME03Cd2IMlFPKHvnU1kiXgquXK/60AvWyefCfD5rPVm1\nZ0Vk1M1mdHZqIx6GQA6d+eRxScDOVWTwbxeff59YVFA/sFwLX/ud3cHPeGk5\nNH3yG4Se+5AUAXqO+JlNG1SUnMClDYTVcvqqwCe7L6ITjaZP3G609Aa/6UZh\nzZrweHjLmhXwBaKvMkkYtsH7UbPjC6+pdIGbsiD4TK8dsgufcQJ2hKqUNd9Q\nTHE1ECjHihBHTH4acgQzPr7jfJGXKtPtMXI5jE2QSEjOjxPJPM+dwBePW9Uk\nf8CUm6o4CInpYE2au5S1E/udY54jMwq7JIXEImfwX1/cP373Xbar3hcb/j29\n/gxmEBLn1ygGiGGVXeqbm6kCxlJqqlIaJGjx+HVcnWiA7Du2KmrTMh4P6zCK\nAW4dVsocdYEm4476Fyodc8BTan/6dd1AAQzFmeEcWLayh2zLZ8YOWFSmQDiD\niRp7iwIbn2OzyOhO3FwAE0C2zISvLqdspKNqh42XCdVRwKwHOFdJgKv13UPT\nMDXu/mQj3fiHcOj4tIJ9qh09vIO27yaHn1BVEvVJF0l0CtsqIEePWzUJcYKa\n7XFnTr6pOh9viQOydXOOh/bx5hH9PdfiEC8b+a2tmwTzyvcID07Gk/62YRc1\np8qM\r\n=ojdx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD+fG1NGz1YxO+/nsZOFlIrLbtORMawia5WRTLhlzzXdQIge7SrVI9fyCCNI3qX3ZRPZFfzfM7EhpAzS9oZe0/GsgM="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_1.2.0-alpha.2_1547180519015_0.3196879535451942"},"_hasShrinkwrap":false},"2.0.0-alpha.0":{"name":"react-modelx","version":"2.0.0-alpha.0","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","readme":"# react-modelx &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-modelx.svg?style=flat)](https://www.npmjs.com/package/react-modelx) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js) [![install size](https://packagephobia.now.sh/badge?p=react-modelx)](https://packagephobia.now.sh/result?p=react-modelx) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-modelx work around](https://github.com/byte-fe/react-modelx-experiment)\n\ninstall package\n\n```\nnpm install react-modelx\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n```typescript\nimport { Model } from 'react-modelx'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\n// CSR export\n// export const { useStore, getState } = Model(models)\n// SSR export\nexport type ModelProps = ModelsProps<typeof models>\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```javascript\nimport React from 'react'\n// CSR\nimport { useStore } from './index'\n// SSR\n// import { ModelProps } from '../index.model'\n\n// CSR\nexport default () => {\n  // SSR\n  // export default (props: ModelProps) => {\n  //   const { useStore, getState } = props\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You need these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from './index'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async () => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\nexport const { getInitialState } = Model({ Home, Shared })\n\nconst MyApp = (props: AppProps & DefaultAppIProps & RouterProps) => {\n  const initialModel = Model({ Home, Shared }, (props as any).initialModels) // TypeScript Support will release later.\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} {...initialModel} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  context\n  const initialModels = await getInitialState()\n  return {\n    initialModels\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { ModelProps } from '../index.model'\nexport default (props: ModelProps) => {\n  const { useStore, getState } = props // TypeScript Support will release later.\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-modelx'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"3edbcb1499ad4c92aa07f43d58333e5bf51c07e0","_id":"react-modelx@2.0.0-alpha.0","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-YyLEiTvxK0IW/8olV8en1vQVNcRdiqrotGTu7gQTue5TXTiyG0mctTh+o8pNWAOdK4fli1bgMrlnRf04rS9uRQ==","shasum":"4631e01aa5154edb6fea0aba5183d2b3832e2d15","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.0-alpha.0.tgz","fileCount":11,"unpackedSize":36339,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcO//yCRA9TVsSAnZWagAA1z8P/3uZU6PenCfjI0oik0NX\nB3GyoHniFA7LehMQvtuX3g6ZE0JLASY9NEiA9Ojp6hqFGQcrORWywOxYxW+b\nsEok1EBfgbu630Qta+1k2fWXlciw6irZO0T9A7c2LJHenvqBNM1jVyMuSMNs\nwBDOnLQvGx4Vui/Uq2LsCZl79Q4m38UFnceIfYysDwAb312kioFe/x/R8/RH\nqA1jt9ZxOgsQmuIURMwkqdmRwAN5H3AR0c8L3nr5U+xPFkcR6Chc+jL4T4//\n7aO3FvYAxuMXNT+a8tb21uqC7UJeMJyujMF/wCAyxngRghiifWtSKAcDmWeB\nLk2wYQHKvFSxZLq6xuz9lII4ywI814mSfAbVNw+cNH/WCvJq/DfH07TxCrR1\nzAeU+2CZXVqj2ez1geZsqwo2zDMFYcM2L7cN5gzPbIncrULrtKyF4ZGl2xzf\n9rIhttRcd97a/8SUMLO+qMIrFAudp1gfCs0clocZaQNpmchNzYlPxPrQBkx3\nKRUqa8Q4hAY6nqkNpUjDHM6SiMa0NSYnfADeJAJxOttCvGb60FhUaaa7EJmE\nm+8xhagOxHPg9vCaQiXOwxDWJkmytvr0E3tWrehPuop4V5/Zyg58RXMqQp9b\nQasBGnzEZHAd8PTNVbPMg0mXWrQvg2VIf1hoPzAskslOBCV4asnjOxOLj9Gi\n71pd\r\n=MctR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCpk2/zJGSTDkqRuAU+CkBtK4gU2wikD3uHrKwyLL4jzwIhALLqN6jPljwbWp1lFr2oYUf9y14lWwFKINKo+L5EDurC"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.0-alpha.0_1547436017493_0.21653150065335858"},"_hasShrinkwrap":false},"2.0.0-alpha.1":{"name":"react-modelx","version":"2.0.0-alpha.1","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","readme":"# react-modelx &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-modelx.svg?style=flat)](https://www.npmjs.com/package/react-modelx) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js) [![install size](https://packagephobia.now.sh/badge?p=react-modelx)](https://packagephobia.now.sh/result?p=react-modelx) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-modelx work around](https://github.com/byte-fe/react-modelx-experiment)\n\ninstall package\n\n```\nnpm install react-modelx\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n```typescript\nimport { Model } from 'react-modelx'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\n// CSR export\n// export const { useStore, getState } = Model(models)\n// SSR export\nexport type ModelProps = ModelsProps<typeof models>\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```javascript\nimport React from 'react'\n// CSR\nimport { useStore } from './index'\n// SSR\n// import { ModelProps } from '../index.model'\n\n// CSR\nexport default () => {\n  // SSR\n  // export default (props: ModelProps) => {\n  //   const { useStore, getState } = props\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You need these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from './index'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async () => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\nexport const { getInitialState } = Model({ Home, Shared })\n\nconst MyApp = (props: AppProps & DefaultAppIProps & RouterProps) => {\n  const initialModel = Model({ Home, Shared }, (props as any).initialModels) // TypeScript Support will release later.\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} {...initialModel} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  context\n  const initialModels = await getInitialState()\n  return {\n    initialModels\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { ModelProps } from '../index.model'\nexport default (props: ModelProps) => {\n  const { useStore, getState } = props // TypeScript Support will release later.\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-modelx'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"3edbcb1499ad4c92aa07f43d58333e5bf51c07e0","_id":"react-modelx@2.0.0-alpha.1","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-un6MWkANYNghh7Qoo1iHL8WlrwEIDkxSk+5oKCBdubvWqEKxS8+Fr2LMVftHISgR8hyKj/EYUbS+4I1sFMmKHQ==","shasum":"f2db1a907b3716838761a8f16cd25d2cef58e554","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.0-alpha.1.tgz","fileCount":11,"unpackedSize":36350,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcPAVhCRA9TVsSAnZWagAAok0P/jbSgxsR/CYGko8nxcCR\nPMW0rhEjS82XYtKTAAuQLA5ny8WBu4HHYXtNoLl4sBN0Tyh8+5ViYCE6qaMH\nBSa3u/6KR16/ZrqBPXeZLmS+YZCC8US/+8YJAm4Barr8uyLR9tXHfZXZZqKr\njRyWdqDAF9BLVD8zlzS3/BNJ9tpkVJBJGR6fu+paevE4xbAK4nBZky2XEzzR\njrs/eHthakUkVDKVVRkAwzVsv8oAnZ8wotR9dJvBenhN+GcABuwwyo9hTJcx\nZCaEmoyGA3rmEy4JopRQ3SCZLc2NEGzUqqnYbEC73zLuH/ZypXdq8Os8kYki\nadlZKpZftl6QzdPLaaTi4bQWoNa6x/7Mvqd4+vbFf8oTuO0uL71Pbd0xPy5R\n7S9Drx2KUn7eEnVSO+yOKRrFUbPLDsd4u4Hl7e5NCvjxpDx6IuM+R3tUweF4\nkIdjYvB1lcpC58h/OU6qGgipOVzt7Htjqq8ovOC1Mu+Z0u2Tu2dzq4RA+HcZ\nXVxh3vt7LkxXXIotNeOOdKy9LLSlPT5JqL5HESEeI1BZyre/CZu8vb9cn11N\nHIAcjnFyFP0rMANUYoskCd++Ex0pgs2g/Rd2UP9yCY37ahH6YkPPiB+SiyLu\nwyUyjD66Lfa+yXllgf2bJbKSZt1jdkRgHepnCV8GCHRs5eS8g9f81HJWmuAS\nr51f\r\n=M8uB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCO48IpcoPaxV6z6VHSFnabRtDQma4Y8+t/Dv4mSEMbwAIgZzBEbAogOzH5QxsmraQp6xKOg3I7+8NUFc46vtoK6wc="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.0-alpha.1_1547437408536_0.3815269324027717"},"_hasShrinkwrap":false},"2.0.0-alpha.2":{"name":"react-modelx","version":"2.0.0-alpha.2","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","readme":"# react-modelx &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-modelx.svg?style=flat)](https://www.npmjs.com/package/react-modelx) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js) [![install size](https://packagephobia.now.sh/badge?p=react-modelx)](https://packagephobia.now.sh/result?p=react-modelx) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-modelx work around](https://github.com/byte-fe/react-modelx-experiment)\n\ninstall package\n\n```\nnpm install react-modelx\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n```typescript\nimport { Model } from 'react-modelx'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\n// CSR export\n// export const { useStore, getState } = Model(models)\n// SSR export\nexport type ModelProps = ModelsProps<typeof models>\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```javascript\nimport React from 'react'\n// CSR\nimport { useStore } from './index'\n// SSR\n// import { ModelProps } from '../index.model'\n\n// CSR\nexport default () => {\n  // SSR\n  // export default (props: ModelProps) => {\n  //   const { useStore, getState } = props\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You need these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from './index'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async () => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nlet initialModel: any\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nconst MyApp = props => {\n  if (!(process as any).browser) {\n    initialModel = Model(models, (props as any).initialModels) // TypeScript Support will release later.\n  } else {\n    initialModel =\n      (props as any).initialModel || Model(models, (props as any).initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} useStore={useStore} getState={getState} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = await getInitialState()\n    return { initialModels }\n  } else {\n    return { initialModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { ModelProps } from '../index.model'\nexport default (props: ModelProps) => {\n  const { useStore, getState } = props // TypeScript Support will release later.\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-modelx'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"f5406832b5c8dffd0c6f6e8eb7c09aa4d1fa0346","_id":"react-modelx@2.0.0-alpha.2","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-GnUjsNClahQcFVRwn5fTfAA28vu4pjWQjAhZmsghppP6E76gRNAzQGZ8Qr0ViXsdMJBCv1gi36FnskAl7GSXYg==","shasum":"afeec5390d55d7d94383a6e1b641b4f8327eb35d","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.0-alpha.2.tgz","fileCount":11,"unpackedSize":36742,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcPC67CRA9TVsSAnZWagAA9OgP/0ooE6HEO4nhyjMiZB64\nO7PR8KWJDXoqdHp6PSTTLJvcCnpKuupjmpz/sRg7ss2eGxXNF1AYO9vDzS58\nllUv9w+3UGkLfrOMcKIS4i3+55tVMRtnKJTayfUCWXCmofuWg+kx/Wp4Eru/\nxqa4ZhbsJ1+HiKYJIetWVL/2FNXNajRAqGmTMTuQVQps7ORxa/2x6PiySH7F\nXzQrXjaXakdsIFmQuqu0laZxy2+oVO2YWZM0gyrbQr8+qbOjW+64kXxzNFg4\n45OgUymPcm677NtsgUx9zNcSWi0ka2jrI78ZAbCpH/pydKHZCJH3Sqt+SCkV\nPbuDodxWvVEtm7hcvCAmDlBtRDeSk3qQ707o7TorAulNQ8TcHGWbvan+sWnc\nP79uPSAWLevv54SETVeDlsbRkWh3Ud02e5FW7hPlWLjOBHOLFQKEuBuOPR1O\nXhaQ2EEc3E/F3zpRn0+jGSvorgtKsdoGBS0vDlqI8cyd7ApJFm2bxjnWZd5D\nrLJhdXC//whwy8W8/oxVndSs2DeDB4QCYiZpnopVznpZjxr7vfhbn1nZaxn3\noObNw9k5pYqSRIP3z/AUhF5LpCZAdas8ouEIR3pkHMDZuYKNA4sORYWwTiaV\nGMsMoEiF1YHgw9oCdc3bYW6Vb5v86RWfLKvxb5RJGb8TjJPhUaKrnXMOJbWZ\nPA46\r\n=FRXG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDteu037H0YC5knRWcSTdDT80p0SVUtN50RGdIBGJ68hQIgdPdAE/jiKPRfGnr8jbtJcCVPG19XZXpyUOPln38ah0k="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.0-alpha.2_1547447994424_0.9918500852732772"},"_hasShrinkwrap":false},"2.0.0":{"name":"react-modelx","version":"2.0.0","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","readme":"# react-modelx &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-modelx.svg?style=flat)](https://www.npmjs.com/package/react-modelx) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js) [![install size](https://packagephobia.now.sh/badge?p=react-modelx)](https://packagephobia.now.sh/result?p=react-modelx) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-modelx work around](https://github.com/byte-fe/react-modelx-experiment)\n\ninstall package\n\n```\nnpm install react-modelx\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n```typescript\nimport { Model } from 'react-modelx'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\n// CSR export\n// export const { useStore, getState } = Model(models)\n// SSR export\nexport type ModelProps = ModelsProps<typeof models>\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```javascript\nimport React from 'react'\n// CSR\nimport { useStore } from './index'\n// SSR\n// import { ModelProps } from '../index.model'\n\n// CSR\nexport default () => {\n  // SSR\n  // export default (props: ModelProps) => {\n  //   const { useStore, getState } = props\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You need these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from './index'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async () => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nlet initialModel: any\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nconst MyApp = props => {\n  if (!(process as any).browser) {\n    initialModel = Model(models, (props as any).initialModels) // TypeScript Support will release later.\n  } else {\n    initialModel =\n      (props as any).initialModel || Model(models, (props as any).initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} useStore={useStore} getState={getState} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = await getInitialState()\n    return { initialModels }\n  } else {\n    return { initialModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { ModelProps } from '../index.model'\nexport default (props: ModelProps) => {\n  const { useStore, getState } = props // TypeScript Support will release later.\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-modelx'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"f5406832b5c8dffd0c6f6e8eb7c09aa4d1fa0346","_id":"react-modelx@2.0.0","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-Af6th20f7SQpkyAgASIaNNozFfiVnD127MoqbFhKMDGIBFO05rS48Uz8ZA8B7SRb5e08e8BbTBFXe+r1z1NvtA==","shasum":"065fdd3105731c3445048a47ca8e8a881abd258e","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.0.tgz","fileCount":11,"unpackedSize":36734,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcPDAQCRA9TVsSAnZWagAAWzAQAILLvgGJELU4941RlVQ0\nXrfGsc9lB3OKQySJP0SfRGKkq4uqqiRMdpl0EpVbD66FmabDcFd2ClXGFh+3\ngiEFvJmN6pyEinBMIFumhzvgPb+1LgQpdfFpEMcuA+wjBk3DQqHOslK/LMSg\ny8kZIp0gzVWzTw1ZPQh2u6IrniRLo9SDCRzSV+88zAfOG5qnNasez0V7Y/zV\ns7oQOE0r43h+8pcSac0aqvBntHFMyrSNcKjY6TRoPbvgwFJWMm5lihQRw9Fb\nM1c4+sj5IZP2dlnr/jCmGiyM007Wo8h+6wMD5GDn80wLgVbbLcH93Sh+qzH+\nF5gVNE+1Ax/V6wlcut/hu5ch/snW4E9kHG6HAaQFZm3Ioa1ipyo4wq7bouNb\n9e9WNNo83F6L/UuurvqhjROAOiH0RpWNRflJqIPazdAERGrmSVYbzs4OuZC9\nrkwIFs0M46Gj2mf36yq2SLM91ZooQdLHNEPKRqz1qZXrLKdQbcmKs5Y+1NbH\nTc7pbf0M7h9FMwzv/hGo0O/lrlQSrsVUV0LIE+2Hem39Bzz//PKAjpVnxFot\neIcZEfJIgdY4Z4RWcbmoPjQpHlWpX9pikjDNpGg9TW1RP4eTvo1bCmqUX1Ma\nzWVL0sU5SrbaH0MLt5fPILrwUFy6Yw4IDfkoz4aLp/PbhevlkleCEHS7pPkV\nxJ8m\r\n=Q/V0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIARmxIokXlqjRcbyYkP2x5dC9c0SMeognzv8qSkYFl55AiEAlZ9RoTLYUsfpl8B+3nQU/C+9FWsYGvWEjRFLwxA2T/g="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.0_1547448336330_0.724763398583091"},"_hasShrinkwrap":false},"2.0.1":{"name":"react-modelx","version":"2.0.1","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"f5406832b5c8dffd0c6f6e8eb7c09aa4d1fa0346","_id":"react-modelx@2.0.1","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-YwpbrmvGCAMoW1ltPFOAWOO6UozeY2JlS023GkRu9neRNqjW+kWESD/XplWBzF1dy2OBCHsfTfdHPcvk6aWRIw==","shasum":"bcd803bf8502c12d75c8de7327dd62acec66eb07","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.1.tgz","fileCount":11,"unpackedSize":36734,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcPDBnCRA9TVsSAnZWagAAd+YQAIpI/BJz5I+iGgfWjL52\nDOwGmNjyGaRUp71p055ot46uLodadhC6gsWh1VFoc5Ev4h4O70RnZLdvfL5E\npc4X2mVsdpPVbcnibCEbBMHbL4sk034A+dvhL3X8RwxTWKDrkBDy5liyvMgH\nOq1lvVbjNW23aYiqBaskwA79f+PAPWZF6hrbdiNquDiYiM6HK90wk5359uvu\nJ/UoSGN/fQkYslUTj+VJ3xh3RHQufnBCyzL2DD/VJt5VIlBaLWKu0kl4UEh3\nj6vMj35ZC9uDA381J5vjgZHnJ8tjHNkqiWowMZN9PWsiGXD0Df+VTRuM8C9F\ncZdlKfutP7llgypVhCkn266igbKtZBYuuqiXWueEcXCabhoL3JXlQW+cfuxk\nSwnOOA5ww6Aow88Lkf5mzNlk/i+wbV5n1MhqtE3UApMbu03v9Z4CbS5TVZ/B\n4ZL4HRqxTOFslFbacbWJCCjifg43k8kc5GHcd9kRkE9tz04MKYPUcLSBq2bh\nPBs9Tc8Jpfx6sI6LSr/tMOPpodtPi5xdBydTo2tDFjocqTBYd8RQT/tPu08A\n8hFku8CGO2X/thU9hYe72DVstyyMxBJRBykvTjYmAfaVI460LAtvGt2ybzX0\nf4k0j2vFngX+x5NqxhnrVUBT97GtOfB1U2N03qfVdBvpXrhhvbwOTkBLgTlf\nw0yl\r\n=aGF7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIH568RNrVT5d28jlXQ+zjo79NadVEoish/hX+NvSOy/LAiAa5wtMG/HG7C0iww0Tp2GUXCy+lrvmNRd3WodFmK5VQg=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.1_1547448422663_0.9240071917723862"},"_hasShrinkwrap":false},"2.0.2-unstable.0":{"name":"react-modelx","version":"2.0.2-unstable.0","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","readme":"# react-modelx &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-modelx.svg?style=flat)](https://www.npmjs.com/package/react-modelx) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-modelx/dist/react-modelx.js) [![install size](https://packagephobia.now.sh/badge?p=react-modelx)](https://packagephobia.now.sh/result?p=react-modelx) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-modelx work around](https://github.com/byte-fe/react-modelx-experiment)\n\ninstall package\n\n```\nnpm install react-modelx\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n```typescript\nimport { Model } from 'react-modelx'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\n// CSR export\n// export const { useStore, getState } = Model(models)\n// SSR export\nexport type ModelProps = ModelsProps<typeof models>\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```javascript\nimport React from 'react'\n// CSR\nimport { useStore } from './index'\n// SSR\n// import { ModelProps } from '../index.model'\n\n// CSR\nexport default () => {\n  // SSR\n  // export default (props: ModelProps) => {\n  //   const { useStore, getState } = props\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You need these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from './index'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async () => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nlet initialModel: any\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nconst MyApp = props => {\n  if (!(process as any).browser) {\n    initialModel = Model(models, (props as any).initialModels) // TypeScript Support will release later.\n  } else {\n    initialModel =\n      (props as any).initialModel || Model(models, (props as any).initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} useStore={useStore} getState={getState} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = await getInitialState()\n    return { initialModels }\n  } else {\n    return { initialModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { ModelProps } from '../index.model'\nexport default (props: ModelProps) => {\n  const { useStore, getState } = props // TypeScript Support will release later.\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-modelx'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-modelx'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"f5406832b5c8dffd0c6f6e8eb7c09aa4d1fa0346","_id":"react-modelx@2.0.2-unstable.0","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-fVBkGKWSFCMfrgwI19E9ryyit5TC7WlQKFetnLe22tnoVtu6IYQBU9SooOZGtGhWgvKdYWNg8O890+16kr7F9Q==","shasum":"1e8249d1dd731cdfe2f7830a773c7cb3ad58c8b4","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.2-unstable.0.tgz","fileCount":11,"unpackedSize":38206,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcPWlLCRA9TVsSAnZWagAAsz8P/0Q5rJIK62RM6xvm8dbn\n/ALwMcBPhsl5NADlw63AzhhvgiMfyTOH3XkDGMqua8Nsrh5xKuoWDbkFEF/m\nJz2aSA1LO8fLCCkrTjUqVUGa5+52TCMKnTal6b19YYzn9PNZ2mneadNR0pNZ\nhpYvftCrHBVKmibN++2OP9PBLgpKJnUbXeU3+wL/2I3WbT040tGF3Yq/Zj3c\nsNJ/cHxXwb2BZ2aYcL4EupR6ayksKMV0LKGR6kwlFkX95zRc9AOKov1MOI7x\nz0LQEx7+fgDFnn1ZH5UoWJRrtY+d6jeYexHBAIzD+eUIM+L1+60BLUlalUHY\nLf402hHexrND1kLAHF8DBYmhODIun/Sj2R3YdFYa8shhel1bydFtujPhtRTE\nTrjGCCt8f3XH5L9ozSlIA82b0J6D67OdeYQM1p8FBtN1JaM2qsxsDjWj1/+V\nGa6RcI9WVcy3XHmGcxUz2345GcBcglHq3IEP3RRTppkX9ByS1b7aliOIV8iN\nxSstKwid/b54D6UPZ9W70Ngn1czeTy2pGBlQ15WOMlRov3qNENuU+ANdMDd/\nPqAwbKzTI4uGyxiNyE8KJVB8PjRuaAicKZttF3wqYlpWCVEWUIUTZjfjNeGF\nRXXSpHVbyQpJHRIbkftxH56goyd8UThPNfZTjs+NBkxsDrkI0YhyQvRmQTbP\ngmW7\r\n=zHmf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCep4RN+KN9qfnsjvLsrU83Ynq2VnIOU4oyUgnAJl8QGQIhAKNRSWiUSaZQC0gDjyx/Rg5WSxdVA3pUGaKfNvPiCFeQ"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.2-unstable.0_1547528522963_0.21837614709730602"},"_hasShrinkwrap":false},"2.0.2":{"name":"react-modelx","version":"2.0.2","description":"The State management library for React","main":"./dist/react-modelx","module":"./dist/react-modelx","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-modelx.git"},"bugs":{"url":"https://github.com/byte-fe/react-modelx/issues"},"homepage":"https://github.com/byte-fe/react-modelx#readme","gitHead":"6c6ce52f027b5243f34f18411a71c3f4d4724874","_id":"react-modelx@2.0.2","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-zniJoU9XR39kVDC4gqgngvw8oExxwX2qu9AaiJ9GcMxjJ5SnV3It3l10e9rCFCYnv7n5WZgGsq27XD3alknOvg==","shasum":"3896610e371a4bb25f3801940517f98784f14a02","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.2.tgz","fileCount":11,"unpackedSize":37816,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcPZdbCRA9TVsSAnZWagAAb40P/RGxKfSlVJP0VIn8F2TL\nuIK+b0F1PIkaBljnHPp1VkI6ck0yeQRpWRMvUgcPELMmOWAMa3pNxvHABbND\nt8eXb5fiZ04UET33nMGYpmml5lIs7V1de6dO3e7oSd/jYiRzEeGvV6rm2H2W\nhVv5mWdHfiVUFbE/1YnMNGm2dl+9xJgGQZEHSdsGIn2mAYKGB9k1+Z12CY9r\n2nMJo9EIQKCKJM3NTg7nGnV3ANkIzq8rNmwGtezlryvjzGIH80atuAgRxSY/\nBZpvW7s7EoHbIbeysPyoAAVs/AZ5Se5NOwlY316Wih9HEhxHrQOg8crBPFs/\nOWru4nWqja6qiGmYzCtJbltP/SEUx2g0BCjrehKqYwnQMYIWHwjVUIJNxYjc\nFtGHK67F7yBws6XqEDSTjHQIG6rZUSpOC8ZWS9YxQIdtt71HrCNI0yX2t4cM\nADbRAG4woSAl2Ug7H0/FGRjWmNpEk8c+PjYRbyEIChZmga1/UctG+j0YcEi/\nckRbxb+sx/4bAx9HnCm6V7XFtR+Q9rCP2CoJU4mRH3ZCaEo2qW97x5mkq4Xt\np1EWzq8mPIhayYbtlr0DesfHFOAvnkdDuyTfvx/xUeUnABb8t0ykoU2QiVq3\nWk39oRLc4lUmZem9LGftlXYPumJ0008EKmK5z2IlIhXHSRF8LcyHtUC2PsBV\nXTuF\r\n=ZVB5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF92NF5vbo6txWeUZb3g4F8bkfqAlotga3Y5Lav/IEmRAiEAheFiPGg7IFIS0jxVEqOYn2IxBD7Kf8Bhz6EAHbD5yDw="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.2_1547540315270_0.5965252522342286"},"_hasShrinkwrap":false},"2.0.3":{"name":"react-modelx","version":"2.0.3","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","peerDependencies":{"immer":"^1.9.3","react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","immer":"^1.9.3","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"68e6c4bf03b2cee40bab06092a8ac08505ed5ef7","_id":"react-modelx@2.0.3","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-7NVj17z+RDEztR7Gmm4XlFEP2rdjoHk9lw+DPKrzLtxbHsS6ZXZ2zIXyIs7RsQvW0I0eZO7FhvsWA+9ouTnMZQ==","shasum":"c5d2811f2b283a3384909fe8a0e0c6afbb5f31cc","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.3.tgz","fileCount":11,"unpackedSize":37794,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcPZmvCRA9TVsSAnZWagAAjyMQAJgUiDZF3o0WBsQO8HqG\n6FmgrqDPjJidN2h0x8VNpGQKqi/FsRVolc7Q6zDaQKD+Qcl75zcZ6tF44af7\n7m84lGzBMtBy8FaSTyKPHiZ0BRFY1GyGdRsXUQltKA/mWNPTLjdLa6L6hfSo\nRefSXfJFYCA+GiqmPcqV1phSFwFTWFNBFslGxGrZa/yEnY/n1ADxjainb9ta\noyxfhKouQB6jHHCnaE3wYrFhQ+2T3tknz/mIskV9jdLylTskFaFJYU+mjviT\nYmLKiB6a/3lQdiEQ7Nh+rTTME317zkQhh11giwhHStTvQV9ewTy7PhYrpfMm\nmNbjQwsYsVr3H74k8UsgivYZjSDYcIftfj1DJ3LnmLqfZJRPFpGuSlXlMKg8\nD5EWbhC0ZetHKwrYatVu2KIRfLSJj3F+kTC5UXO+gRAKTmnyW9sTHTIOAGAt\nM49ugSq3wtG5UnEPxMBsA8Bhi8bQq2sPlIAiq5tY40e9V2DSyxc9TPKLvfme\ntbTm428nD12BIAyrxYVzLAZuh3EKHArDafv9pBNKGQAx1JBQ2xRPhVEQsGg4\nOcDGQ6bQOwJX/BVKKq+nLPmCl92cq9rvFXeUP1C2OSfCmK/+TPD13W/oit5/\nNPnm7aMlFrmGnNwuefYXFo/lorBD7U3GxDIeUvrYvyn3MEEyNG56BzLJ8+5u\nVX4S\r\n=eL7G\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAnvqLP+qUXnU91k40OPfyKaJs4sExJ0SQ0Rz1isf2W9AiEA/sulS7a1jXFd9He8DVwWNIb9hFropC4MGytOXWVdvc0="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.3_1547540910851_0.6444587169611475"},"_hasShrinkwrap":false},"2.0.4-unstable":{"name":"react-modelx","version":"2.0.4-unstable","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async () => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if (!(process as any).browser) {\n    persistModel = Model(models, props.initialModels)\n  } else {\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = await getInitialState()\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"68e6c4bf03b2cee40bab06092a8ac08505ed5ef7","_id":"react-modelx@2.0.4-unstable","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-s8NDtmgOqa/o6vo9NaXnjcpJGuzsDEiM3VtwtXoEuOsX+LE03SB9jg1XLgtZirzdS2sXQSy3XEvOdlJGh8rc5Q==","shasum":"99444ece111164cfd53bd57df2909beea305a786","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.4-unstable.tgz","fileCount":11,"unpackedSize":37804,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcPZs3CRA9TVsSAnZWagAAFUIP/3GgAcI8d6jSXTcJ3gAS\nY6XOKhmyTt4Wh1GlcP8dWhuapIeR2vhgAeIVzUZXg/izLTGlvE1yvmyMibiL\nQf/xbwKwX3qkRk4twF6np8iJZLhSeJvRlRpLSSV+tZVlaZJLTh4/IfKNmFe7\nR9964ZYGGoClpyQyQbz+NyRUMKMm3eFCKJuAnGQ43i5xscwyYWoasmblyllc\nYbTJ1nn/ltEA8sa6GwmDx72fC5sd7OXIcfxQ52XCgrramtCiW66OBgXCOjd4\nYmM2fZtANqQBKL2EQXK89jKZKl8qkEOElnKMh1MSufPg7ZBVI1lu4xf1pX+A\nTzA8bdxLxnU8AHY4emP3AvFLuYoC6w5lSE8WfaCifh+14YdW7VQiSmhdrYtF\n1WuZIXjDHFWAwBkl7chjn9ZH5EHeb53sArHbTVii4zoQi20AIMOVMpwvlt0d\n0Gxz5lNUfbmFFnNM+X0RXREz6rBzL6Q/Fj8j/Bdxk1GxLBZEcOi4ucHiu0Qd\nfwoJcVxS71YM7u5OattLQS/grmzo/rucE3JC+2+Pqjwo+2V/0YvNHVzVNmOR\nuBPf+h1YgUOxAm9lgQejFMTCK/1VtrIaJEGi+ayrrSlGbOl2AfMGw9PlyyaB\nJIjpncjFvBq7DLb3PHcF3QJst+owCMkK/az8rdSDtK88qU5svm7izGqm7V1M\nu9lm\r\n=e4OP\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCHhvzW5gTcLnUig72Wlc312TC7G+3ckTNgplCjWL0LZQIgMOF05JyIFkjiHn99gK1V4QxX9kDXFIhdHlDwNlyYSwM="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.4-unstable_1547541303515_0.2107790530204965"},"_hasShrinkwrap":false},"2.0.4":{"name":"react-modelx","version":"2.0.4","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"68e6c4bf03b2cee40bab06092a8ac08505ed5ef7","_id":"react-modelx@2.0.4","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-5lR9wHC0tph15QyYRd/HBAxfwJDjxwRjhYORiCQWx2QQrAIsg4xwh1+oZ9bTM28Ns2yfq4ZC4ATjua+X932zoA==","shasum":"d5a775e074b6954d2b8355eacb936dafe507a985","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.4.tgz","fileCount":11,"unpackedSize":37795,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcPZuMCRA9TVsSAnZWagAA86kQAJdQ5dwBM5OT4ruytcdB\nnNzRV35gT4CrbOHMJf8Y9nT4cs1PcgQtm9Ju0YAMazFfuZwzJF9xGrQnp4Zn\nkCLhlFJNq6ke28IzWKKniLt/lnnLs2cbaU8mGX+Ucg23vk5bdV7f/4M6fQ3X\nND2XPA3Yc01iOB3mJZ7xGZjah3BpniKVv1tmmI9n5yX9cluHM1EF8Pq6OjFj\nUKq1S+S95+aKwsp4zCUj+jJYZOX/VAvCwdXvqeOOpvhaT8juY00aN+uTM4Lw\nv5VPsZkEQ6t922nH8Ad020XXwyGd7A9AUdKpQF8s9OT4LTSki0TzJ5/TzO+R\nzVwnNr+b77X/6rSrDP3H8Yft2UiDc4wmuYZPYEvWcK/xy2N1IxAz1dmhe7WG\n/FaimLdm0ZC+EFaErec7FpaOunpXIGcso6wzNMS1WnfkEnxJPRQt00OsnpuA\nPqvVk9zJQ7BXSfzP4Q0Dt+d5TEe1XoSYhG1BYXexz4PhfJecpGwEudO/odzl\n0ie2TXXbgDpCJ7qwttA8GiNY6Jk2WHwjpCEq2hMWLHR2EboZRlZx7+OtTJMm\nM0euPxBpmfPDEVS0jlwtrIhSG53+nxpyf7eqa37hRqOjwT4ynTEXzeXFJlCv\nojrTEgHTkSs3PDdVO836E4VoU1wfH9O6VCaW1bOcZOEv2P49ZHw+MbQOdZIG\nEImM\r\n=dE34\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFmex3O/RJSfSuKYGmQfNK52okqhoF+isztaZbqyLJXxAiAv4KZJLbKneL9ZgyZ++dnKhZnxGDGdq/2WeA8W2MchLw=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.4_1547541387693_0.8469213496956913"},"_hasShrinkwrap":false},"2.0.5-unstable.0":{"name":"react-modelx","version":"2.0.5-unstable.0","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async () => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if (!(process as any).browser) {\n    persistModel = Model(models, props.initialModels)\n  } else {\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = await getInitialState()\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"68e6c4bf03b2cee40bab06092a8ac08505ed5ef7","_id":"react-modelx@2.0.5-unstable.0","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-DryBPQtkP2+ursyBcvQJXzG76StTlF6OF7lvkgD/SyLxpTNj8FyUwMBGVM1H5Zwz0X76WsFzReoS5zXuh230uw==","shasum":"e96168e87ff6064855d492858a2cb1629253099e","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.5-unstable.0.tgz","fileCount":11,"unpackedSize":37887,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcPuTOCRA9TVsSAnZWagAA/PYP/iOQJ1dGLSGEMxMXx7es\nTPjn8e42lceKgpdKaCy60oXhNohYM7eVELBufdmt4RcOvxj1pWgFfvaKXtHa\nlhYwaL/+VfePmh5Krlx9s23uWfMJov1OcKPQZhGMwuB+6fNhhcOnazzjqwzT\nvgoNvUWu/o/x9h2MrES3/gPWh6iJhVTcYlPCTfI7rj1WQMtmR3vmx18EdByr\nQEFI54B97/sGGCg1jXAqsH1U2sNqV6GayTsyZte0JaRhBBOdxmBm4Lfovcbg\nGKKF1oF4R0AZKrE/fQ/jqN/RV2+bJjUwZqLzSXuoW0MSVsViNWrLkqSXC98O\nW44KqojyWky5m7M9DPHZXxtwZ5ArNEs1jDtEAkhOrrfGeJOll0Vvoas5YCSX\ndzNuLczhiFHWPMunaXXXX7eLzI77/dgnF/SrjAHYb6luueKNobhvRc9hz7cy\nOxZ46Pf9FKUlYFSIibUIda2AdaA8BQqGvRIlQNyPeknmy5VHbMMHIsBinRpU\nOkKJkyviH6EdWyTEd8LHmxOpVYhAsqqXJRxT6mcFbuOKYKDlwYFpazBmk3AI\n4YuXu3ifxV3a/AArr2dush243iv9U30n8rGqtzbMMkCH5vF6sY83n68K5Q73\neyfLtx2G7NAPhlG5NV91NEYKV2sl5vmd+GbgJHkmpfeMTAySDRCE8MpamHFw\nUX6K\r\n=7ov0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDMEWX9/itHR4XX1PrwYrFxQKyfOvZI+p0sL6WWmA1R4gIhAK2m0w9CzX9mw2oc5i438T6Gky168GVVOuKqvLmUx2lM"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.5-unstable.0_1547625677919_0.110118764192493"},"_hasShrinkwrap":false},"2.0.5":{"name":"react-modelx","version":"2.0.5","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"5acebedc55acb7ca85b8ced40f11f774949a39f6","_id":"react-modelx@2.0.5","_npmVersion":"6.4.1","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-ROBOOj9TeDKDUESG+4fOeLlHrE53sYRB0BQ3U8fBQtBcLKc9+Zojsnuad2VZXFMvOwbvUXneEHkxF70UPfhEQQ==","shasum":"86757a2d38dacc081491aed2fd833786dcb688c6","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.5.tgz","fileCount":11,"unpackedSize":37876,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcPukLCRA9TVsSAnZWagAA98gP/Rm04ERZ61StfCti703M\neiEzt7DsZ67ge3ebOCBjtkibqREZfP7cEo+zhyrOZq+TGXS9Yj9HaHCLDK9O\nL68RMLrc/SvpckEcvLmhALVJhJwIkBU0RR6ygFwLWd5kODSzTvTa7XiH6ws2\nXFGPmwoOgim4VxaFOQ4CAun8041WhzD/F3TJrMguS3UArIKaoz+Jz3s95r+0\nKJd6kWNj+YSMSzNmcoPHwR8UmbnEI9ho1eddIQothIi2Nrc8VkBmLPc6EKw5\nOC/2IW2+7Sy/lwTCcDlzqE39cB5mdCWlP+qnKgRAhtgHcW5Q8lbONR+BrN0g\nMAKRiDRP1jrkxGUicmY+uQDUC6nYBSpmosESd11RlSQ9/ssCNJ/HzWl5ek8j\nnuwL8zW46rqfkFc0VnVH/OouC0Fi//Bce77n9wml2RuLawGqqzpYIizOqcXb\ne1LD2Ql9T8WSasl6ZucHVJFc8zdtz+4JC5HAB3zxeiJIKOFKL+0FaQKsq4MT\n7FlxbFyLuNPqwAF3wdKV7Ay5q12mm+thF7SrhygRUb/HTAh/79K+Z9coxu9C\n1V1OmE+Ubz5lUEQgPK/hPXDxc8WC7HpF+cQ1tk2TdJ5HKSMFgHpUDTCkt3TO\n4yXbBr3OvC/n/fEExj1RJuSjmWlYOZjTXWhmEdVnljygJNTAAbwWDXVPQWVP\nEomY\r\n=nh1J\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFubwTwE/HrMaq5/60SSVMiYC/Nr/mLIbJrGoSt035J9AiBSvBmQVIZQoaKsq1ucJ/BycIamZwu96Q56C9LNmISf6g=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.5_1547626762602_0.7254319156560243"},"_hasShrinkwrap":false},"2.0.6-unstable.0":{"name":"react-modelx","version":"2.0.6-unstable.0","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = await getInitialState(context)\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"1f552ea700b50c66586ed13d78e2bd900c7803ce","_id":"react-modelx@2.0.6-unstable.0","_npmVersion":"6.5.0","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-c0qL34aA8+lhjCN4w6S50LchvBYXWXBMJMwmHpmd8QW9i7NFyGxagQZXp9/k3/sG1IPrZY5uz6EedTk5Qh9nFw==","shasum":"2d4211f43fb5af97551048dc7aae0ca57d0a5d3b","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.6-unstable.0.tgz","fileCount":11,"unpackedSize":39473,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcQJ/jCRA9TVsSAnZWagAA4uYP/1X/WE8XyptWLiANBDNA\nDdOEkX8O+3zjxrei202aVJoxJD9U8e/kFd56ZKyC2venwRZrCvzf2fa0oDZh\npXAHLBz4VbWwdeWg7AP4bkLiqddkKUm3Aky1YzHVokkmRvXhJBnrXLsOEO+O\nOiNBuCDmxK8RPMbuwGhi4qrS76WEE5jHj7FPxdc3Yj6udN4cL7wLbZONw0zx\nO7b5qbgnl5hJ12bbDm9eUDTfzSF9KgALlgksHkV4A46ej99F9VYgrxmcyhK7\n3RSpZHh5fY2zeHvGpao5VtBzpmox9aN2M4f0SSrsTcpKCsX/rOuni+q+L/nS\n4tjVSi3fcLUu7lwJQHBkbl+8DhrRJP88YT4hG6b4sENkBbwEA2ZNFiWHkMxQ\n9nrrn9Rpye3iMtZLPZ6lXFV4iy208mFJQKoWgvCFkPsg88fOIjSfDAN5ee/Y\nRiMgj+cbIaP14jmm35dbi42Tl18mbyFGxsR9tiEvCpEY4vDIrb6orYIs+ux4\nbmAL+VMNm4041TOBVKzDpZulralm6Q9K63+NZGsEge3hB/6/igykjWEUamrH\nWGpFDkx5fzfwo4wUTHPg2kBXgvOD3TdwOwF19oeBmtVTGaCKumHXi1zCB/gr\nBzomUCefiG0/bAYOApsxe87NuXfMEwqLR223JlXbqWvc1uwumYd8Q9ZCDc8O\n92fu\r\n=E7xE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEMKRNcZ4Rf4mPFsN2bYk6dOdURoVVjypV0qyIHcfB5NAiAibm1qaDl5qkKEMHZcWaEUKQV1r2mkRVVhnXRzizfcbA=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.6-unstable.0_1547739106576_0.4619000053315452"},"_hasShrinkwrap":false},"2.0.6-unstable.1":{"name":"react-modelx","version":"2.0.6-unstable.1","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = await getInitialState(context)\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hook\nconst tryCatch: Middleware<{}> = (context, restMiddlewares) => {\n  const { next } = context\n  next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"1f552ea700b50c66586ed13d78e2bd900c7803ce","_id":"react-modelx@2.0.6-unstable.1","_npmVersion":"6.5.0","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-cmCjdkNPK3v8cTNsmOTxxEIaVCftabtiRejPwsN7mh8z/cM5zBhZTFnmK94h89irG+El0ujXnkpGWvVPM+f2lQ==","shasum":"a6ddc9541822b3361c65b812b15330351866356f","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.6-unstable.1.tgz","fileCount":11,"unpackedSize":39572,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcQKNpCRA9TVsSAnZWagAAVikP/3LsfFLS5Jy+sekgfNLh\n76kEUn4DBmQq4OePTLx/bLFIXY2mJsZFK4hEhdYJPS+va8EZwyvyFGOg7mpf\n4UGUu6/tek8kLb+HAQboVvNbB834k7XYZOsIz4eQY6JCqyN7zbOH090lBmn5\nZmIMrf1sX1dnk/OLgjBgTHWEkZa28tNmuBFEF+XQ0evOTkQTgww69n1bg6cM\nSItgyLad0QfemLkSIa5r4JUok8vjThVkEkqPOdBysvfBYuhVrsipcZ+jPE5q\nO5+aC+TpTAt42iDX1h5uWoF8I7mVALT2WMn6S3BADvMZlIU2qRMjAZybmDkz\nkF8WCDZHR02O87q552icRQSND+Sb0D43HJeGF1f2uhP0C/OoQfrYBexrm8Ft\nWs4M30TYzAjJjs6gy84yMh6/MfO+r7t95mOXLSvoBsnbS/BV+/V4ssrCepIK\nqHXmdAVTSm7EYrBnCrZ4Zdv9Oh8Mso6xigRTfs7pbW71yGrKI5fuOSnlUjDf\nusWiOMc51fe72a+OMyeJNg5f76T3diRiup0uY9fRO92CtkzkxnduoD9H4C6y\nzW8BCwtbkKjn1Xtl4rHVkSWt2O1iKlpJaSGpkcVoXzGtmVT10Z1o+O+wcyzF\nD3nDWJss66ZmUyMVWRNGPmKkMZbXRQ5sZQ2qXdxVnxlLFc+anfzXSEh/KV1G\nesXh\r\n=+xnT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDH/PYgvVjPjQqo5Ou+rLlR68yE9hp7rPoXzV1FiDOoOQIhAOOJjKONDCG7rm/JLBcFTHsP0upcpyVX0/dJTyWPGH/k"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.6-unstable.1_1547740009348_0.3299370575289864"},"_hasShrinkwrap":false},"2.0.6-unstable.2":{"name":"react-modelx","version":"2.0.6-unstable.2","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = await getInitialState(context)\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"a9e1909c927095af804936b0483e2475cf39e492","_id":"react-modelx@2.0.6-unstable.2","_npmVersion":"6.5.0","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-lwSxY8q264BgWkqjIa0PmT0x/Sa6SpJT635M6sJjH1tpE3BJEckzyRFVqx3kc3/q2cr6ytzas6pz1FQ2eGz9Qg==","shasum":"883cc6db70a297739d8130fa80c5669a2d67165d","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.6-unstable.2.tgz","fileCount":11,"unpackedSize":40220,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcQLSJCRA9TVsSAnZWagAA8XMP/0Yn2F8eL9cn6bsqEFT6\ndKiV7+A+cinp7u4XNlyTHIm9PZT7JT3+9cDDor6hv2+RlismNrrlwarxjjHS\nVOcKy4BElU9aRwu4QYEMj3RmJca4EO+qQBDdqjJoU8dk6ionPmNrdtDac2q2\ntrbU/3jmIj4XoPRtQi53NY5W2ZBnzKn+Zd4ymrhzn+nHl41YDJGiKyDtvkSA\nLBQV8x+1QmMTRKzjukqjxqz6IJJxe7JpeDUVx+QUQtZgQKsti7NTrxnDyD2g\ntX+2r9VzBGEL194kJ2DncW7ZfXTGq3c6ZbhAuOGIO5/JQVrNFXjeIf6wzq0S\n+pCpxBtG2kF52ip3Y7l4fMbivdMOJZdAltvj8Ql82WTczbS8Co8IpXKYCWjO\n7Qznph9R5Y2gxpfM6lm8F/hLQymIeDRfnaIHsxs3MKu0aNGpryOvEAWOMAXu\nXfp2Aj5SmmLQCP5973rZor6/KkdzpEeAjkYS5kjN+1DEvRBC/317ErVVF+bR\nhL0d9B4RFlJjPjExmSiKnyuM4+W4lPJKxLgd38y+FhNJR3HzniQRhU2Kv0pm\nadNxws2r+vzPkLT01a+q/QQXRDEG3hzSvKTcgfYAkzqZY0jhhzZ+oGm9W6ml\nuTeye4fZAoAsy2XcdBHc86u8W2cv/P+i54pTP9TvFwQlS25u5ULzSIyQJhFS\nTN7i\r\n=BnO6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGkRnBs02SQTlO6NJRs17EWI3t2xXKvEgQ4ak66xttSbAiEAitBx3z2IQIRCozRztURdBnVuSkqFkfqWmEyplloz60s="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.6-unstable.2_1547744393147_0.781057448897805"},"_hasShrinkwrap":false},"2.0.6-unstable.3":{"name":"react-modelx","version":"2.0.6-unstable.3","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = await getInitialState(context)\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"a9e1909c927095af804936b0483e2475cf39e492","_id":"react-modelx@2.0.6-unstable.3","_npmVersion":"6.5.0","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-BADTuynOy1gxuHrA7GyO3eK+joAJfyosG7ek+UvcxLKbU7w6Ec1K/pkyhH3nUqDyXIIZAUZ2YYY7UnlBAwp+yQ==","shasum":"4b8249a61ca3322dda44f5466d0ef66a7e3396ab","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.6-unstable.3.tgz","fileCount":11,"unpackedSize":40319,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcQLWFCRA9TVsSAnZWagAA/YkP/2cnicRhGI+KjQ/4YS7g\nM51AZdrKH3SK9a6kKDZnrX8dJ8yPdVp56pdrwcsFwapNU0JNU8cgH1AaYKga\nYoCr6BOtbKdSg4tkwwM5zP3dvxrDScHHR8D6Z12F5j6jjUpyfXtj7+9d866w\nJ0SRbjYRQ1nJu+MldsSp9EnBDNpsnOWnfb+JlZP9n2XrgRv6Z3t92oPs6TaK\nbG/xNFMg/eiejt5oALoxR+Zrla+PooZS7cmVGWQPPggziync7s1SFH6o3zbm\n9MS2JVr90gmz73Vj7Mltxro7x2KIz6B7+CeAhZSwoEf6sx078mw+ZehPzwe5\n3AvnnvL1Si9FYu0WSJ+1QynieL/eFUHM2E60OKSoh/obchIsjgy8DgGNjwDz\nDzOgeRjBP/kXyJmodl8uUl3PTqjAlnr5sSCgiTjZmfcRhZpRi4dDPxsnNe+s\nyf4/n3aFF92AMi1rTF0MCGsqtsmpgHXNew6Yzoiyng1wBKAPwbJllmL3SjdE\nhhegRbJnAJvGRXtX4CibWckD7jT+D9Ckvj6Y5c/FpgBFI95/Lv7aRMPC7tZz\nDmmSdtXomM/WmBSbK8CsNB2GhWCN3Enn40CwBIVeoFe+OI5A4aBqSk7pQRO1\nYkmLftpNmD4ogJROLKl8Cr7B31tFHEt/APkNoD8FrcWyAyuqtQcLCuRwAHF3\nyAAX\r\n=gFm7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEA5U8y9uP0uW9ekHJDadKfe8Ie7x0O89gsYMwxRqsvaAiA7oCxb1+YV8KNNGhZX02qwfIKLS8da5k0ERK0C+fINbg=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.6-unstable.3_1547744644454_0.8810888578661713"},"_hasShrinkwrap":false},"2.0.6":{"name":"react-modelx","version":"2.0.6","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"e8e28d45aca5dce86b70e70cc49f86360809607a","_id":"react-modelx@2.0.6","_npmVersion":"6.5.0","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-n80nUXvAPDiK/PG7GUe4wFhsv/BszpGrk3Nn/1MrvHGuDWZwUtaWJHub3E17mfnXPuaDNP8iGvR28yO6z6nGFg==","shasum":"98538b0e432dd86c6e665350f1c4dec435390ecb","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.6.tgz","fileCount":11,"unpackedSize":40308,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcQLitCRA9TVsSAnZWagAAqxEP/0yzPbNpOMzaN8B3fNzM\naLwC7STGkwloagtlc1KklCPG8Rn5KKs/8+dcZaOcPA+X55VWaWnVXiZYvr9l\nmPbVh60L64SacGar0WHyphGv2ie26gh44uQotzPgic3C7x0zPBbE9h0cPz3i\nH3qH/CL9/6g1/n5fhVweGKY6QsH7V3bbN5X7YSV8FuBuByWR+uLskHTw1/hR\nVQo74854cxwGuOTrD9/SGIQjQMoGjxpciyAXztkbj+D4vyRTw1bdGYEcE8x2\nKxYsEjndrU5barFloBBYtg7ZSAqriBR4KkrcxKvhsbOBGzPVNGIpPcz4USgE\nBQEYy/44gVUinjiAcs7TtgwJQh7RKsoSyPV3mrn9M9j3f1pLVXUkJ0obmwMv\nd8W8c911vNlei/5rmfR0ZamF22iTWbKjo+TluLGp0VdyUr1lPiDPl9TMkGAz\nixvGFh41UVptFGqSEJY3okqcRidf8iopNG8RQmCu8b2Ylqf5wUOoG5NJzTZL\nY3I3Wahcn3Cz5aiFFoxdJAa7Mqfdh+Q1Epvoqjp7tg3BQGOrFoQ3/HhrmxmZ\nnE5I/eXQVqWraUIHCTNXa+A8SXsXvyhUGY28xT2oxsTNxMgHVTGEH14YLDDV\npzzeLud0F2EPQA0R4W/xYcw6dBLVPyl4PkcN5ZoMcCyIbZDxw5QbLWvMmFx3\nW/Yv\r\n=hfKu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDu20V+e9pfko77lfiy3vrTKjoUj0s8R6Xpr2qJPKaBVgIgQLyB2dFb9zSa0nEQ7bXQHXYgqI3wCRQ8FlXkRAmpa48="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.6_1547745452977_0.12819744734093774"},"_hasShrinkwrap":false},"2.0.7-unstable.0":{"name":"react-modelx","version":"2.0.7-unstable.0","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = await getInitialState(context)\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"e8e28d45aca5dce86b70e70cc49f86360809607a","_id":"react-modelx@2.0.7-unstable.0","_npmVersion":"6.5.0","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-QrxSF5LFGD/iUqtsu90yjdIKLLFCiH1Q1xkbsB3jRNIMR4x/ep+drg42/2HjfRwpHizveYJs0MfQ1Nh+ix11GA==","shasum":"5cc4e33431f985eb766efa1652ffab10aff11cf6","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.7-unstable.0.tgz","fileCount":11,"unpackedSize":40760,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcQUihCRA9TVsSAnZWagAAtsAP/jf2FbaEiGBMzVzDs2Ng\ndtZPONOQq/4vjSzG+bGbaeTxNBZfDtTXKHuxWlyy1uZz6nddqCCw1NrTwlVf\nShV9M5VJ2TrG5aecEf9vWTz/bWaAX2fHYq7eZaJEGym2ZmU7hTuCjhjEWgFx\nCwLxKLdnlMnYvTIhvFfLGYRNBvP2RwHSiqUut4TiL6yFR5DkS0gG4esbRnF/\n91W8BtvWXaULez8ZxX06tj3MSMJY70Du2gBKqSslkzsWWvjYFhjdp8D8NwIu\n2jmjrTaUn26giDcdYpO12yqDuD8UGSeI7WoiFAVztQl7tl0w8iTT2RZjHLcu\noXEh9d0awARk5757Y7IPC6a5ASK3yE4RTOPJntPgVNXjVrUwiSOMRnK88nu2\nGyOFdVIyxCFncb4SXy6fT9P0aoMRF8IXLR1afT+rSWMVD+IvhFijKtxbewjQ\nA13BLhgm56JUFcvSMt4205RR2gaJ4q24QQLFyQg349zEDfJCaCXzvPHdemOv\nQLg7h8IhsXYQRmic7qezfwgA7TB6K6rmT1RnCgB+szY219VVEQjycUNx6sDj\nvZE01ulwskQWCpJ3etBbcZvXMN/7coHDfbnXslG+EK/wB+hZpzGplNdEW0lT\n2gtCruSQLQVdtya4JfJp+LYur+GZcOdt52za+i052KQWTkiR5+QdTUmiX+oZ\njYUy\r\n=yc9e\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC7usnPt8wnIcFdIQKBfxCpUi/Af02NjV7dNsTPKh7z9AIhAPsf5UcAX3vNYxkSUo6qv2zYV+Wx/qTdY5FXUc2YeUN1"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.7-unstable.0_1547782304601_0.8815888141918811"},"_hasShrinkwrap":false},"2.0.7":{"name":"react-modelx","version":"2.0.7","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"e8e28d45aca5dce86b70e70cc49f86360809607a","_id":"react-modelx@2.0.7","_npmVersion":"6.5.0","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-pH1up0EDh8TZs6UAQVW1p7f/Wsh/Leh/RBHP403DvWx7ABK8UePFPJC9E4U92mPyjh87OvDO3a3jdMNlvoYmWA==","shasum":"0f5d6d0a7898ae4c01ddd162782196dc951f8294","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.7.tgz","fileCount":11,"unpackedSize":40749,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcQUsPCRA9TVsSAnZWagAA1x4P+wf7PQ+lCxfbFdgmQanM\nJi7sG/wu1vyL2J8OTyUHSzh6kS5Q9nJEMrqUQIpiqEb1vQb5ooAEhJXxZNU/\n+XkiBEx6h/DJ/1bW9P4mytt0S+K6OESinK+tq7F3AoApIzeJp8EwPoKv6MY9\nEY5fUgW4Q5JmJvlvSUEFah8xm1gy7X4KG1uP+ASXi1j8EUbrxWPXuxSfqEFp\ni6ARjg8CLeBe1IY1CV7pUhKfyXQ8bJPeQSMQptevcRfOw4r4v6sxhRQrfv/k\nArhjd1jpDRTJAvpZ5HbRs+5iy/jLhAYimr0T1f/XMO8wgqPUtfIDRy3L2MND\nnSZA9NIeQa4yqmnpWUGjXDdmV5FbvkNlpYWpz2G6V3vgSuR4O01zicQVveJp\nuIxVK2ipC1gacsx7ned3eu2uRyFvgMQJz+pGh7VbTscVaxDzoevVk9Qc7PP7\nr4nc8iQG688D68ee/ln2CEia79ABdzOe7x5WrHhoLlJCAQPMdo6Hg26qEY/o\njSQA+rK/AABXYpcg63gukbJx7vygxFhTMzAMmvBic7kclkbynlHW+qWfc/K/\nZejG/oUglRYtx1CgcVqxFhqKN0zuXZoZ76frm2aeNFMDZxOIveXeigkr5eDa\np4x7Ws+TUXJVWainVHcKo5uGXJvmW7BQyujQ72B2fosnD6rnIzNWkTxh2FBM\nie49\r\n=pMdK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCYQC3RH3BhwC0YScvy/NGcBqf+OZs0fp0W3KUJjhZTCgIhAK53DHZuEYsOPMzWnYcMF3yg4mDbNX53k6oHSD22zS8B"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.7_1547782926659_0.23510120650449284"},"_hasShrinkwrap":false},"2.0.8-unstable.0":{"name":"react-modelx","version":"2.0.8-unstable.0","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' })\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"e8e28d45aca5dce86b70e70cc49f86360809607a","_id":"react-modelx@2.0.8-unstable.0","_npmVersion":"6.5.0","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-QYBoJtrE7X2JOkiOTh1Jphn2g9kHqCUxOS20K6npA4sl5T9Rt4VMgs19YicZvVXxnYkxQK9PlfvcEsKJncut0w==","shasum":"9acd245a46df35f5dc1b0e305c88d85b9204007d","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.8-unstable.0.tgz","fileCount":11,"unpackedSize":41117,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcQUxCCRA9TVsSAnZWagAAXcQP/0I7kaFH3Ue+eN+BVPMo\nA1e5h924cjuRPdMFD28AB62CySkYiz1GupqwIr0sBWRIxxW4C/XeUo5WvbCr\nS+9lCOaV2Hfazv+MBi718+gEqz+LML7j3FpQIVTnIXgoEr74jfOfMkbfg2JE\n3rZw3aFWXPDN5b8YezTvIJHL4vljjjIycLq/pWl0NfFUamIvqGRdF9Rg2vhN\n0uDTbhvVNYxUSJZehLYR60tmdyFLsWW46uFxL/soLTKBr1ANrkchBp7rQgzI\n9OJMqPaMfum6LKtwLg77piWSoQkuM9Nd+fglSMir6wpONuz3CrndUOdrvaZc\n7x0mLd+TeyrKBVhDkbiRGsg01q5F3YwZUDXN7diKE/GQlCY+Dk8SxsjQV1cJ\ndUNguZcscMrN+cjZKRRvgDGUL/B6VKLuqwNCFzzqtKZYmFFjP2jcNoiC3uzm\nvEHBmJiagMV88lGnn0lfYrECSNP+WMuxAeMvKS5oTqVSGheXwHV6Y7QUH3sE\n2Ie+8UiGSSAxxBQn0XNa0HQ2D45CVEos+LE1U7oo2dC50zuOJZ9IJICD0xkh\nQpwujuxUdVVvy3l349O9VKxzkz2weE2bUqW/i8j2u1HdUZyUpBN4RwLiTIym\nHzOgxYGbjL26RJaSBcG3v7YzxeGOld08DfC0y6RqupxETXtbIxV9zoX+i0HE\n+ni+\r\n=I9nd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGIoVaoMh2rY83eQtGtRzY0hOZcc+cmZ75r+4g7TzX+rAiB1421EAoGU6ix485bnrfFwdlNbysLb7niN9CdBflZKSg=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.8-unstable.0_1547783233636_0.9499308159266573"},"_hasShrinkwrap":false},"2.0.8":{"name":"react-modelx","version":"2.0.8","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"dc103e496508baf9dc758ee456c093399727cd2d","_id":"react-modelx@2.0.8","_npmVersion":"6.5.0","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-VSKuWxaadZPJAamTCUZqQAK7zlrPvJgo5fSS2hrBgQClcDfMx0RtZiXDi+9tTkrnPf0T1MBY7PY7R7OHUG/RFA==","shasum":"f1c4a026cfaf153ab97c2b457e88862a64cb2b5a","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.8.tgz","fileCount":11,"unpackedSize":41330,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcQU4MCRA9TVsSAnZWagAAOrUP+gKbTYUSTNLsyfCT9++8\nRpSi20yaXbzVJMk9WjssnwatYniqlfM8vewi0a8QJ0/xWmYXsYRXkl4L6xJy\nMwdgRXhsWF5aI2r879vsUgBzKIYPJeXF2FNKVEz7QXJwSBzhKLHCVyaPbGjQ\nuFOhtLLAG/b0RnNfTtld+CqugBhQ+HcALqD6XrGEXv/JS2STt9lbQOL+xTHM\ncU6ihpjs8Sgi7xORm4GBY/BpMLiQRA3g1n9qtBtsCpNwD2K751mVdM56ZV51\nkBjkRpU1TKqUxKBz4TvPoInrEXHQlOsmogldFndmW+lMJcxuY9pIyV7ddxt7\nkLd6HmdNZBB29+ZD9kpVdvrMehBiqWBM+x3issQaIe1gsDWwjEPOKwV5uDlS\nV91TbdxDaDq4COpxQQ4+BrTcnU1xQKFbJ1bciLhTQ+0eQJJsm6z9zy8GR5vy\nawKDR1naZgjvjlvcv5Rfhggtb9uNz8v/7cLlwsNHyJYBus3zzDyPWNfdKBiO\nt8lOspxXJSBKTL8eyfy0SDl3avPqYmKDpxOnYtfO4+7uMkcHNov/Sq8Mf5QQ\nodHwx4cAdnjr7MXuDPZoT+nYqieW1HtnBsKLb1GZcpZSIhkLQV9AaKg34cRi\nKXUfsH0V5QUpEer9u3O5E+kQYkvM2tHJ/01zNX8TbYPBB6FIKLoDEOVEnR+c\n3Vl7\r\n=10c+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHJISlVC6ReaMV0HOFWwv0NQ2R1H6RzMFUiVtxQD6rwuAiBzLjNKMijaNAe6YrXIUMejyWKtjToXMQsU/dZqAlxpGw=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.8_1547783692376_0.43939009195290324"},"_hasShrinkwrap":false},"2.0.9":{"name":"react-modelx","version":"2.0.9","description":"The State management library for React","main":"./dist/react-model.js","module":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"ea7da61a55c4045993f3989d8ea5a54724c3d401","_id":"react-modelx@2.0.9","_npmVersion":"6.5.0","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-SeGacAFYX5t9ehqg+/cb+D/hAa2JSI22VRIF6TXFui/9r7sxtM0wWrUXh+nOSVDz0olPf/MO9hXXwugHiwOoPA==","shasum":"c8c56206033deb78cf8792f6b0dd04200232c9b7","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.9.tgz","fileCount":11,"unpackedSize":41417,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcRH7TCRA9TVsSAnZWagAAKe8QAJLKLi/WmsN/f4Bq18yo\n/MUeLPAnIDMc3Da8S6O8lC7JD3HQz9MmnEIV5LUAZu7mz/A7Q2EoYfkGBOeW\nCHcNTfXzGylTsVlSHkE/hhBF67cScL1jxPDZyWjU2MatJXQ6eFSGEotutSDt\noDF6NcpK1EekSd1mqGUpriYMxv25rr9ICfDgzbldQA/i+o7Z4ixLqRnl5CwI\nidd7K/uEz37YlJxwpkcTjQlyj2Q2o+5x0BTaBXv6wL8e72y/KJR+NfU4c5CO\nnpEgdov7Ht/LWKxf08Km/AwNhxcLeq11tojeheMEyhj55AwQ6ySihJHtUPK4\nT31+WxtFQtWcvXsq9YeDx3sX3Wtxdhe1G8ywb+2OQkRrcS25zH7+kKOGQuFu\nR32SsIMHrw0mWMAFV84CVCOrAh0LZTor5L/MnJOfmDDTo8ve3EYQMFFN5BGd\np6S9ZiO3hjdOYGkdgMxWjaMhmo+8EC1OJh/64y6wb3lOaoXjKzSMCa4fRJb4\n+FfXkomuhkRLgE2R+ITyALFFKjh4FYwmf4fVY+kvUkbQdwQposZbHkuJ6URT\neZTz8g3EgcF+5w9E1Cl6njZVBcDwNRv8s/9hm0dL4MCOZU9CBhA4dJdgodK6\n1dRt4E3unZlQjx03F96VNrNG4u+o4dQge5lBSuGiSddOChYFQbW6ONMGydxh\nUe/a\r\n=D07a\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCSz5HtSa5db182udQgsHIkH5Pfmj1z9lQBgCUsFgtbxQIhAMLMRxCEGG4PjrSQNl5sdIzl2SRjtzHPhUE8mbz3oafm"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.9_1547992786455_0.5952808890405994"},"_hasShrinkwrap":false},"2.0.10":{"name":"react-modelx","version":"2.0.10","description":"The State management library for React","main":"./dist/react-model","module":"./dist/react-model","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"e9710403d98948df10b2f58480776181968a7f33","_id":"react-modelx@2.0.10","_npmVersion":"6.5.0","_nodeVersion":"10.11.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-qPqQ0FCJakn4v1/7+Bu4C1Q6H33cJLOuBkNfMcT8krho9SrdCCMVoEQfVfdslSosjfldn/pgst3yMbwoOV8CrA==","shasum":"3333646bf92c01cef79c568c8fbc064ff192f8e3","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.10.tgz","fileCount":11,"unpackedSize":41498,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcRIFjCRA9TVsSAnZWagAAT7cP+wa5vg6G/hQVMV7WwPUd\nB28d2yOB/YhOpITKzKeNdEY811iVu1KYASSrWeMYxIl+iV8PZcQUJks+9q+y\nnNR8iVvVubNzuYoBE29KEyc4m4q6PieZROmHW0n0cj/Vn1cj3z5so1WZyqD/\nDQoXrHNnn2kOaYnBxsh48gaBvL7FgFNlJeec6D6fIHTs1OzctHd/z3yPwaIr\nkjgWhl2+iV9LQoTRWwktwjYxPzyyIiGawSLyAxn8SR1p69CMNApoPVmoxZ8w\nhAbepEOv21486l39WUUACdIwOt3CiTV2iuyHEEQ7NN7Wm1ND+9mI0c/lHQsr\nZj78WEsigK8GHMl4Qi1seWMv8rktArpUKM5ODv0Zh2Cs0vQ+TrzuWwuvGk4f\nHjcBx3rLQWdp/CaooZn5eaR8L7JBDG9Ft0MiC9x1s52L/n2/n6A/P1D5wKUt\nywqGaOMprZ6K1XKx8W9ARD8MuqkLIHsJ+FcpVegtaDPfztIauDhUtD4oUajy\nFW2+AcmuC/q5r28genl52t0rU+N9R9orp+EGHhI4zUO9WOH38pZ+xMxxnhZ7\n6wrgGmM7T2qAdDZuG3mRX7Z2iIYQ2P6VLQbTb9NYHELZyMk9KakW+p4TSMDS\nxPjiwVpKnfSIoSefZasGFBY+J/mGrmRpitq+gE+1MgN5EGSvNYkOZ2G8c9K+\nfGyb\r\n=jRFs\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFh2kV+MGb2rHCkZEqLXWAJ0fW0QwDfJFPo3LTPWfSUeAiEA/JLVuqGN2M1XL6eaICYuZTSWmRCerW/eHgTy5iyLExs="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.10_1547993441915_0.6957750791787467"},"_hasShrinkwrap":false},"2.0.11-unstable.0":{"name":"react-modelx","version":"2.0.11-unstable.0","description":"The State management library for React","main":"./dist/react-model.js","module":"./dist/react-model","umd:main":"./dist/react-model.umd.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"e9710403d98948df10b2f58480776181968a7f33","_id":"react-modelx@2.0.11-unstable.0","_shasum":"2d3683e7795aafefd175ce0826c320c63da74915","_from":".","_npmVersion":"3.10.10","_nodeVersion":"6.11.2","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"shasum":"2d3683e7795aafefd175ce0826c320c63da74915","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.11-unstable.0.tgz","integrity":"sha512-h/EZ3c7+Ix5gQBR1yRcW0tQRyV39DcU43JwzqQIO5+8W/MgzTIUYMp0mhI34LjZwDYkUeUCC5AewLAaBi3fh/Q==","fileCount":13,"unpackedSize":43827,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcRJd0CRA9TVsSAnZWagAA9ucP/1oy+kc2ieWAOOY2lnHy\nL9289OO8/NQ/IE43CaaD9UWQT4d6pPvyFlCD8JSNtdk7yib+EsQkzq6Fozde\nkXRDng11lA3APE+eKCywI+e+nwoAVy2Lw27TMS9cy7KlLDJh0excZGpMpNpj\nI1AxEomHk//Lz39cSpu3gjl98scAEwSPI5WI/2KRpRLmSGeq/fOuvg4elUPB\naZSSNwsFxGaAmTV8PMFSrXGwUDGuxJ9jCMjJCHtuokQPX1rZU8wkS8ZtJosE\nTfb6NkrpuGfcIV93+ka+/jW9rUhcyWPsrnGsWiw6mFGhQIgtw1ItudLc9Szr\nJ03nxd6cTSj/rFLpiTpJR8RuThhzfpRHZJuS9YkuRazyIoom0kQcklMYKzHD\nRG+ofi6oocHhLp6kgEzRC9r/wXlIypYIHyBzkt1Uj60YLHU6teJwK283P5lw\nV2HEQTQB8btQbs2zxKxDD3jkJ3gogCXkap5r2M5IezDY//FVCVvajO9nc8Dq\n4N7jcolmkPlf8jO+tC41DOiVv7vQN5C0LBmlW1Ld/MqwcZuf/wU8zSLdyoES\nLulfRgLYAHtUUjI9rYznynuxA+AinQUGuWFLA7mMdwV8u5yt+Eo3vomFhFah\nL+zNqjUdvpUDztlkD9MvoApoP5Zpmu9doI7AMwSSiyWUOlfyPevd8FPKqVuk\nbLsC\r\n=Tgz7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBR43o46dle0AdmCRf+nWVYiTXdx9nfPjCgbbfRnY7dZAiA7C+2HJFsQ86xFxSwfeoOzZOXFvt5qNci15VcSjh89RQ=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.11-unstable.0_1547999092324_0.38261602411754847"},"_hasShrinkwrap":false},"2.0.12-unstable":{"name":"react-modelx","version":"2.0.12-unstable","description":"The State management library for React","main":"./dist/react-model.js","module":"./dist/react-model.mjs","umd:main":"./dist/react-model.umd.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"e9710403d98948df10b2f58480776181968a7f33","_id":"react-modelx@2.0.12-unstable","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-co9hNNDTu3A85x7pk7Psei2wc76TzPDVAMUEYucGdtMgNAxYN6yUvimNwBc0jz+4+wqXIOPfXkhHuYaKhzFtWw==","shasum":"801c2e828bb19d508182e1a4897b5cfd04a44828","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.12-unstable.tgz","fileCount":11,"unpackedSize":41579,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcRVmpCRA9TVsSAnZWagAA90IQAJir5Ur9vz3NcF7U895p\nrGiUQKLHtznHtauWLEmhA7Rh4PPqI/tkWEi0dNgLRTW7xEJUjeryQAZuPN7k\nw1jEpDgwhwr5HYfBXFcngRQNs/ysmMuycLrK99kPykjUSW+QACdZiA9RsYB0\nybLwG/sx5TU2g0w6niRwRnxTwwPieEfIPLHmAjD5juK2fWbMXcaH4Ffv/BSK\n/4+r0EcMImNdx/tHbIJy1PatFsTmKD0Y155QI+saZgvxuQvnbRvZw15in9DS\nitsoNAvlpZq8slaOyYWPllWFP/5UaQf9x/GdgZprRhNfZj0qH6sRfXxrB63h\ntio2Wr1Z6/KXjczeJMfXmrJ4p9h58QwwI4GZXh6vlFBxTm4fGvt2/zpwF+mh\nAUlchMhHVC6fAszM9qU45/KIqQTgHsiPIFY3Lzh0E2Rh3hzfTyy+2tNfePr4\nDnhpr3dsLbZtKOm6i9m9o3U4QvyjoqfI0acKGdMnt6ICGFs8/PQqp0H+HCog\nExLM+qd/83BJOzG7ukAvTYJ5XqrT1jzITqycFsKQZUk/5zeLKzETeBATzttW\nMucog3Qy1L9WqdEmR6z+zvYEUY8gZuqRWlBAIJWs79mUMbO7kfCbs0X2KtwJ\ncZFe8kbSPpEO+OeqjWslzFMDjtaWmoz8n/K9zfURUz8HhZjoYU/F9eJAAVKD\nnd+M\r\n=s/x/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGWjQvaN9j/CHRJpO96OMwHiGZU+wlASLplc9Ne+QU7QAiEAgz/vx0waKm+H46Zekpdqvubx14ifHfPOw0E3ONF4Gh4="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.12-unstable_1548048808573_0.03613954017824095"},"_hasShrinkwrap":false},"2.0.12-unstable.0":{"name":"react-modelx","version":"2.0.12-unstable.0","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"e9710403d98948df10b2f58480776181968a7f33","_id":"react-modelx@2.0.12-unstable.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-Yek7AjqzUGl0mwsWyDfQoiACfY0HPXjLKrtwfD0USjIzTxT+cO1q8B/j/HdnWnI4gXGfLiAbnPFVUNTdLrPmVQ==","shasum":"8992d6ebacda3dc797bf413d233f1fb0f2e9cf0d","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.12-unstable.0.tgz","fileCount":11,"unpackedSize":41500,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcRVvmCRA9TVsSAnZWagAAfJYP/10RAYVr2P9T1YWW+R8M\n4WmMmXDMKRLYba1aKlGDEgld+XrfiLS/IAjoUI+pg9kCfzVaT6PippdD9ZeY\nlggxCCvymvmOKwni5LuAN2qTFY4r9xLIhw2TMYdF86FtS9dFbx3HlPPgwAyB\nIttJxr9+gRGTbPsYA5kE5BDys2OCof6Jzj2WCxqF9lXvNpRlesZ3fN9o0i5j\nBR8yyQMs+nVwhFKaZfPRuNeNIxxg/Kd4cO3Zcx7HJmLZDVTSu8z8Xi7c74Ga\n2cUxNdtMoLfRTnVEUVx3lNcolRY8zbkRJbPdAUGb9lAHwvY14EuCmh+BOVsr\nHCbUy/tPCLcpZL0twyZQ6mP7ZQtU9IPDw+6kBWZjv5tKxjh7rOLwYcO5FcF9\n8kpTyh84cJ5nK21ojZHxMebpr4vS+sa8UAGqteQuLPTCMmu+MNadI/tgnk/J\npht9igH/Mcax/ivijYmrY9XbZXcUKKevua2oBd0jkznAmnKfKuCi/YbxnkEZ\nUe+bJO4S+n46nb8FhWTGGNkulPXwccUC8N0D16/qSkgAkU9dk/kz6awnREEN\nJK+d4WEjs7z6JLlPn64udXWFk5pHTVlstJqG2w8WHpWsUEW2/KKcSnM1W41o\nDMKOuu1WjywUwDXN5jOIKoX6Hzym3ec5OgwjviODsAwusKgwZ8ds/9c3VHoT\nPS+M\r\n=bK0d\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAsqozmZ5poINawq+JcqCyO5XIMGiV6kJtYwBuGOXrcaAiBHU23uJMUSqotn6TVckIL30HerCvFJR16vWWMCFH+n6g=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.12-unstable.0_1548049382331_0.24158234885582708"},"_hasShrinkwrap":false},"2.0.12":{"name":"react-modelx","version":"2.0.12","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"e9710403d98948df10b2f58480776181968a7f33","_id":"react-modelx@2.0.12","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-LLqMXQTbxJpFJqRq5zcLYklkycM9o32fm5x8pUaY4q5boWJhQ/3/hLDsWhZhweMvH8EKt7M6KEVMzgITbROhOg==","shasum":"b97c8eb74f7484673d43f6bbd224e5c664825cb5","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.12.tgz","fileCount":11,"unpackedSize":41489,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcRWPuCRA9TVsSAnZWagAAa9cQAJkqF8O0We/wS9QTLPB7\ncuMKyixKuGTypmXKAWJJJt14E5B75RsEXl78XJl1DaF4juqADwllCj2AZ3ar\nGr5ZHOHpbYRWdKm65AYVhvuHPhRp3sRuQlnue6ARx0tQL/Zsf7Lh1eaa8/Mm\nbOgltycHZFUEThqDEqd+SqZ7tH1CVlQCZx80nLBgf1nDdhCvB3bGIjqOmzwO\nemuOrd7SVn2uyE0MF3O/OcjSZqA2uYrXwH41nCo9cGOX+kAM7aBjQrswygFC\nPm/GXiqWox5wR4v4w4k3rXVD2PFrC5py5LzuCmlwpffQA4zpISlXETkYGHrS\npjgreSFLW8ggOi7U99ot92P5P5Ajixepv1pbxknUTO2NwvYSeuHGD6nDT6KO\nD1EQ/VomUw4OxFhe7WTxl8OjppOoS/G3/P6t3kYK5LCWrLZrJyTLkCj1ua3E\nRGSXn2Bwmn0d58UCWzg2h5oAlt9ZgH1tVbFDycHMXTovAKLWGPSu69rZjTTw\n3/W5Y3TIHKAlurZBdTULCGqXHttLbUU/KNnJdUBn3Qzr5O0CJTxf49iQKUW1\n+KtPS5wGbboqCMCtZbz88TY4kJKUTNvvToeYFsrZh5hQ4qo+VPGoQJbWIcBM\nnNE6iFnL/4QuwfUklXqg1ezW+x+aqDWwGlWY1ZQRSGqB1oCs+QWStn3dbr5f\nJLEv\r\n=5gkp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCa9nHXRzy4jiEw2RhrX2bCrgkNRsI4dHygNFGTRGzgKgIhALqLwT1TXh1tBNmuqSRF+bqaE3t5hrZ9V3URN6qfC4SM"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.12_1548051438379_0.5348023192943263"},"_hasShrinkwrap":false},"2.0.13-unstable.0":{"name":"react-modelx","version":"2.0.13-unstable.0","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"779bb9e87e671496671497a42991248e3e95f286","_id":"react-modelx@2.0.13-unstable.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-eKUwCmOkoAnTl/zlYbkCRlfj79USDJ0oXCnHg2Bv7EWV1Bp2J4fpYFT2OXxfelQXo4c1igEc6j32BHlLnXPh+w==","shasum":"4601bf2772cd1fc68ccd5ce4bf973ed7a728e928","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.13-unstable.0.tgz","fileCount":11,"unpackedSize":41516,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcRerpCRA9TVsSAnZWagAAM4EQAI8AWf2jjjG/nUyLNlTt\nLU8W1qZGREO2ebUtv9b5QfiZxOQNkp/vAFSJPu0suYrPMN+QxcmCjP1vL+IE\nQUm4Teh96GXlJMAZsM3BIeqe45UGLkA8Z61DmVy+8zxdLDCdsxCzRR+G9Cph\nK+pKd2WCg/RSVLmIwHo1xmqbWTSDk6HT27LFOoY4XAwEtivzTQA+hJzQoT7e\nD29yU0U5CcCbY3E8x3lQSM0lVv3nro2YFiXIOKqks89QmMEf+bcY+ZrNMSJh\ncA6Ew/dEQYaPxj4hX46qhrAq2Zb3OHRPc9HVHqIz8duPjM37c5j0DWgXMslf\nNh8nOUEvpWwCiazWFRSjZDhj9Suza1JOumjFAuagRlFlly+N+DJ+V6W4sUDV\nEwO/nYgo9UbGIHCbEqJu5B4DXsjMUlWu9OX6pTNYyQkh/P5jWD3WJdTcXjeU\nFUHyql4/o54MN3DE5fP5NukcdohqYqcGfzlYyf7wNLN9IWHU7xlApat6/MU+\nb4KTsds4KsmUsrGZWOM/h0+mCrdadrHr8p1IRX4LkmjFyZd7pLfB7VQsshmK\novJfPvYqWG3ivIsKuq4IfY+UVOq44rBJwHRFkXjy/ZtpB0ydFfPSdRUyughn\nxeTho2DLhbq22/0WP+ErNtvo3GroI2sNw2atsGD90SjqAxesodh0L21jPhgE\n9Hdo\r\n=muiv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDT3SkDmsQ/CNe+CAYSzPj857iOP3iYJANyilX2aSezSgIhAM9GVQpWUxOB7O8z0mJO734S6gVq9B4H31ckG9zYo8k+"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.13-unstable.0_1548085993117_0.7365659853852613"},"_hasShrinkwrap":false},"2.0.13-unstable.1":{"name":"react-modelx","version":"2.0.13-unstable.1","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.7.0-alpha.2 can use Hooks to connect the global store.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"779bb9e87e671496671497a42991248e3e95f286","_id":"react-modelx@2.0.13-unstable.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-fphkEpaSoGHJxovDkfscFe7QFb44YjQwx6oAtcNgqzJpXzKvJYPjXPUvmiVvrkwitajYX+JP4wSjO8659aEO5Q==","shasum":"9f1e8ca21e772da0df9798d5e5c0862641500959","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.13-unstable.1.tgz","fileCount":11,"unpackedSize":41438,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcRo5jCRA9TVsSAnZWagAAKCsP/RIcunR/1NsQp9h+hjEj\nYJ9OYJFL0HwsSJwB0NlVHX3xzY6pPzbAIOhnsX2+01w+28osRA3rLZHm3LFE\ni2fVMXv/330ZwOa9Qwikg4FcCGtLRm7BH5Ob92pOER8dn9SX9ifUkMoPTcs4\n0C9Eqs9RpwBEunETKutk3NgZSKcq4bt9A3zDzrQNugWPd8aOJeSdVM/AGppK\nNJ0WfhEFEBKNgv272WWd/Ijlof3KBNHhp2rWzLkIeoptCW49E446lFYR8e6O\nx28c/utlb2veKurPcdFgxwKIITHguzG4GPiWk23o2NfXe/9Ihusl1N+p86X8\nvIJuKRDVsUsPnBOGIattxI0uL6ffuh3FwCL+48dSbLePVR8qFMqRMhlz3tX8\nItFBARTf2m3T4jhpp+yFN4W83tXQ0y142mKTTJVBtEYRu1Dlp+GEb4Mn7O9O\nW7r9/NvWpwkR4SC8mpioYKuT9TsO5rIT14nbPdT//hqjRx56DBjcVV1SfWKc\npJERBBNPWH68WXrWjaxKpE0VlT94UWM5vBSn1l+761PDUhefFlqz6+whQoX/\nlKXHO+NIEgKmbmoRnLvrm3GAM9LYgnPXXJ5rMKXN8UZ8BB3ekVwz7yWc0toV\nQngetNYXJE64scyicUdLdRb4oyEk7lqKZK/HNOB22Kk2W3w9sERRI8j6cm03\nyyuf\r\n=xq70\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEIWh+OQ5Wz5vIbkBCHTdYPtb2WszF5l4vWA0z887QHiAiEA59A+hsMtwKezhlXdDRP+KIwJg1NmDqEJwegd4AgHQRs="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.13-unstable.1_1548127842914_0.8534671125722797"},"_hasShrinkwrap":false},"2.0.13":{"name":"react-modelx","version":"2.0.13","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"779bb9e87e671496671497a42991248e3e95f286","_id":"react-modelx@2.0.13","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-Ctm0xU0FS1WJ1ihy8eUHE01+tJiRit89W0nn16+Ii5ipDSjYcH9Ubt8vLOD6k0kKnwbVlFXXEwOZ0093EgBBNA==","shasum":"d17ce1dbd2783ec072f6577721db7028f4928e3a","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.0.13.tgz","fileCount":11,"unpackedSize":41741,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcRpA0CRA9TVsSAnZWagAAcRcP/RrCOJb359ZZFTQL4+9a\nCAy2s2KS84jR7vIE5GyqGwCVBYi43p6UJW1Zl5OlRgxMV1kQlvTsdM0jUQSy\nUiNcqRVx+o/S5M/eGCVHDsvKrFEk+HMQjW9a6DE5hB1/rAkKQjdKyp3LGqeC\nE/UQLWKXhtI80J/bmw8Hyfpi6wMgQxGNzkbCYzygXyrLXgZwwXw1dSvLDCx4\nNRgW9LY2jvmIcPFEiJxBN50qw2FvWN1hFbBE35ZarBNfoNgLC2qVIaRO57cr\ndtbbttvRSBAA3UNdEqQHzuveVl34HcJKsnbykw4um37z1kMQ/apC2o8IF/nv\nwJNqO5MezBVnUt6GXpEipTKIcAV7zAJ+JKvqR4SXhBS+syFEbCsEhungUuNq\nzqCbHXPvCUKzDcH09T3BKy3dtGwtALjd297s8SmHsVNtK8477YSbEAqpPgWV\nEwxpE0+x9rUYJpuQPKvDrQgW4sqmfPPMpCawyUYgnqGv/58jFnkXw4Ae7z7v\ny/jIBZfVBeU6Bsgq0BFkyEDMXfQ4xuX6eICtjUuQAC98FjoANsWfF8U/na3M\n9uBV4US+jESxLx2vMPSPHra7GuR1PMgVS5HskaMLOXxG8MkweEH3UfYwtnWP\nBMYjpSsJ2B8FN3x18mPG66vr+4hCoXt1UiaJb7Ja2Hforio8qQUv9PROQeCt\nRaAQ\r\n=uLUL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCSL+CcElC6BGzBOABNpJvHLDfDRDfjjSkBEf7I6yJu0AIgNHO6lZ4or4m83y83jh/NSRRWmxtv6shI44QAkYPwA5k="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.0.13_1548128307781_0.555967533260946"},"_hasShrinkwrap":false},"2.1.0-unstable.0":{"name":"react-modelx","version":"2.1.0-unstable.0","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.9.3"},"peerDependencies":{"react":"^16.8.0-alpha.0","react-dom":"^16.8.0-alpha.0"},"devDependencies":{"@types/node":"^10.12.18","@types/react":"^16.7.18","@types/react-dom":"^16.0.11","typescript":"^3.2.4"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.8.0-alpha.1 can use Hooks to connect the global store.\nThe actions return from useStore can invoke the dom changes.\n\nBest Practice: Dont use useStore on the Top like the example below because it will reload the whole components. You should use useStore on the subComponents which need it.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\nNote: the getState method cannot invoke the dom changes automatically by itself.\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"7d838ec91dda21a11037c881c8a69798cb975517","_id":"react-modelx@2.1.0-unstable.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-NeUZ8A1M5rHuJ3BCu68kIHcb1UFjDgp5cSJ8Uw+uHzyiGElyBV67xPjV8NN7303KZ272e59Z4FEkUPCiwN6z7A==","shasum":"a8f51aea54b32c4e71631f7a9adc9366ee95f5b7","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.1.0-unstable.0.tgz","fileCount":11,"unpackedSize":42312,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcSJKgCRA9TVsSAnZWagAAJSAP/1Su8zm8fCoCN410vxHG\nMJvbl6X/P4S2BaVwW+9kyUMJwcC0bo4ji30HyeUH3IRbxEMhWoyCjY8OvU7v\n0RFnLbo9il3Gi9bmsk+VUZebU6ZALygT6fITmJgPssW7jyt/et9rkV/PHj7R\nH6PIBdM1inOcqH8zY4pxkVNn7meeHMaH/MwD3u95mCIS413fbjI/s42GXQy8\nSXN7JKqOiwOfHFFKCNjrQWscdGpcI54OqQXHSIi0fZLm81whppiv4trm1Q4S\nuRUIDhQKZYuqx0Hx0M9hh7atiUqUv2bmpjV+WOrG0ApyP2m8Q4vs4Nt/RL+s\nf3DLcvemxCrjecyo7Yy0bB8VXwR6pwWW/QnlBz9E7FLNgsBOb2NJTG8+F1wA\nkdLeoykop8z1rSM17T2pOGM6XJ4RArHdmVjxVeTqlj4hfw9ivfE3r14g8DDi\n0kFJYBU7+MV7pD2uYAz7kstR3LC8jQezxfRCVu6J/pCFoxLMbzUK1gBv0KT0\n0HbxJYwa9qosuM/tyk+3OrP+NX5Drft4wApjscHf/8UnSvdPRNFVx9KnZIwZ\nVMzYUxQBJMChGiS/2VLiHEvQfKnSquyVHdNGUDyXXuCV18XdPozo5NtLImD3\na4/c3QjNgw07ARdX7E9Fbpi6/dfwIdUi7ZA7UQqgAgJ+CMu/Ht0rVeGVrND4\n3jTC\r\n=M+zH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDR9/DPVcI+84CAGsqWldZKiL0eQ+ei6mO+BATJMdhOWgIgXpRD8GbpvcE+f1iaWnK258r3ImBwWKSHDcydGMyzIno="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.1.0-unstable.0_1548259999897_0.7475620910625744"},"_hasShrinkwrap":false},"2.1.0-unstable.1":{"name":"react-modelx","version":"2.1.0-unstable.1","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.12.1"},"peerDependencies":{"react":"^16.8.0","react-dom":"^16.8.0"},"devDependencies":{"@types/node":"^10.12.21","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![install size](https://packagephobia.now.sh/badge?p=react-model)](https://packagephobia.now.sh/result?p=react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Quick Start\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.8.0-alpha.1 can use Hooks to connect the global store.\nThe actions return from useStore can invoke the dom changes.\n\nBest Practice: Dont use useStore on the Top like the example below because it will reload the whole components. You should use useStore on the subComponents which need it.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\nNote: the getState method cannot invoke the dom changes automatically by itself.\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"bd16695e972a7be27a60ce19fb1b98d6e6591e2b","_id":"react-modelx@2.1.0-unstable.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-665HYzppEHDBSRh76j6Ad4HWtKwjsPrWvphlhxWTeU17JyrFkEvpoIinyTapXb6RR4aOuxJ0liRNCjwl94kvAg==","shasum":"4d14b42ac873068a2b8ad5da0603430fcad58a96","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.1.0-unstable.1.tgz","fileCount":11,"unpackedSize":42295,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcWvMZCRA9TVsSAnZWagAANfkP/j971XO0bWqyOfHcGjFO\nR1KGJZMO0j+anE08XzbgFR1ID3rUt1/baTlHhwACjJGfxYI3vUD5+oR9Aq9z\nAebAfxb1jRhufv0YSU2QdtY3knP/4cd6oCLIYSrZesKI4K26lpLvH2+hpmdt\n8pBrmWdNFcsbG8S6gfZw5gBI8xdxLxfOpsPQmoVlzgONr130QRK1jblMae2+\n7fQj9TEZNZch1+vVjXq+aZB8BMp7uq4xOo0pRJvCdXMewe0QKKvnNfMFT/Xf\nzvVE0SxIFJL16PvfeRDhKhM8Ao0ju9+BBuz1yHDY8xXB3wrjMbY0ak4AFgM/\nRAskegKXseKn0wmw2XRDe6XaVG2t5uj9lNLzUu+cJx2sc1E2R7VvM9bRnR1u\no4ZUfiwvUj8aoWtrf+TkRgGnMIbyujPyAZ5NrzxBC2JP5CyQeLulquVN1bi+\nHnaqTEvmt6JtMo5uwZwXTA7kMJB0utzw0C4AqZqyekLMSlZ+/5MhJnD14rsi\nLYdeKR2fQ/c97O1gg3Fq2qIKe1KOHHOM1BqitETszOUSHBbI7DbrQ5cLds2L\nsV4sbZLjPaiRfYhNndhrbEU1MjhExEFbnRiN1ULBjr2B+1+q2ml9Xj12nf4H\n3d/1b9ZiGvGiYWs40+5e69Caeh7X9Mi95vTyG05MpWzTNkRGecDNUUc7wMGW\nkXVX\r\n=55P8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDpRREHFS8FZhcOSjmFZrTtdk910jwKZxFkwv2xWB1nQwIgYEy/wOkbH8//qnsNxt4Xf3HV0cD+lCcGYxxT3FEUmH0="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.1.0-unstable.1_1549464345072_0.8667859497917181"},"_hasShrinkwrap":false},"2.1.0":{"name":"react-modelx","version":"2.1.0","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.12.1"},"peerDependencies":{"react":"^16.8.0","react-dom":"^16.8.0"},"devDependencies":{"@types/node":"^10.12.21","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"bd16695e972a7be27a60ce19fb1b98d6e6591e2b","_id":"react-modelx@2.1.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-RnuXe81ad4sDHS0D50mW4k23njJpftyjs67hsueVa1Dl0yGEdYOIauRPFMAEQG0WRs2N3cNipYZ0zs6djT278w==","shasum":"3bb7a93d1fe32a60564511d9149f32c0c00408c8","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.1.0.tgz","fileCount":11,"unpackedSize":42284,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcWvQBCRA9TVsSAnZWagAAq7oP/2nJ9hEOTFzBwAX1fzzB\noVwz0Hc9TKDf5chm65K7s5Y8q2VwzOdEbwjZUWlm1eUb9iypoiOcrEqytBjQ\nP/BzP3NWG/p6JdAj2w5JBgXIjTbRNjxGdZORRmxqIpwXy80QveEbriOsn4o2\nmQ9H1jCf/BZI8P4ZrXmmf4gvnhymsje5P0ZnuW/N2WtO8vm8NlwSZEQ7D6yU\nXxveSro43rmjGt5r2eLAXscn2Xz2NrcvjQq94dKuLLczOu0Yrh9SqBqraKoF\n4sf6c/YQn74Fj+eDpPOlUbl1qdp3Rmyg1PZ5oF+snouyAopd9e92dI0A0QB/\nRjObtpTVhi+IgFqcjmFgbokL6xexzR9fdpEI19BJ2DEPd9OlKY2LYZ1xKnkC\nD1BvOUqLWD97OWWABA8encRcV3JkJhlLCkMCtG5kcbnhseH3fLbamc9uLBh/\nEgk/INlNn4uHauT/L1XO6EduOsoTIVq+jkh28CyuvJMje1F7iipOnI1GKYBS\nkvsaLZ7Kd+3LOjURehi66Z+ie1/CWqn5F15r9s8hu8CH+gbV8qRGsnYnM5W+\nOoet9G09iYk/hMd9eMYfeIW+veYO5q6UpV442LZ+VHEjncgIDQYMCRALgdCc\nGfuoAaVpuixtDcp9DOU6798mICAbzIaIgUgAnUzCPzMpg5T5seFAukbTStA7\nZH9F\r\n=L545\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCfm/gjUsjaOdEmxTZvrsu2zsCWT4P1zDP7CkG28V6cvwIgXfNPtdyah/uPwTgyYV1kSmKL46ARqGQYmDlPzLHQ9ro="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.1.0_1549464576459_0.14015979211123408"},"_hasShrinkwrap":false},"2.2.0-unstable":{"name":"react-modelx","version":"2.2.0-unstable","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.12.1"},"peerDependencies":{"react":"^16.8.0","react-dom":"^16.8.0"},"devDependencies":{"@types/node":"^10.12.21","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![downloads](https://img.shields.io/npm/dt/react-model.svg)](https://www.npmjs.com/package/react-model)\n\n![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Quick Start\n\n[CodeSandbox: TodoMVC](https://codesandbox.io/s/moyxon99jx)\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Table of Contents\n\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React 16.8.0-alpha.1 can use Hooks to connect the global store.\nThe actions return from useStore can invoke the dom changes.\n\nBest Practice: Dont use useStore on the Top like the example below because it will reload the whole components. You should use useStore on the subComponents which need it.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\nNote: the getState method cannot invoke the dom changes automatically by itself.\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"73d5505b2ae78700b45d5a7360a1c9a63aceceff","_id":"react-modelx@2.2.0-unstable","_nodeVersion":"10.15.0","_npmVersion":"6.8.0","dist":{"integrity":"sha512-B1TtOqTiBvYPxRRKZo+1xU1ec7xkH57MwRURWdLyBcGqdIdPRvFwyARPDFYXlvVnznCAJJBGiSiXRIdY8VE4WA==","shasum":"c6ff3792c1fecd55594a17edbdf4d45259558db5","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.2.0-unstable.tgz","fileCount":11,"unpackedSize":42606,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcaQYdCRA9TVsSAnZWagAAzyUQAI8VoV1dk20++TWRICh4\nj6tPfv0/mTdOCQo9B88gKZm/rV4JR9YxPhUlIAS4zh1yRrIRAlnZNbh1risG\n7nxaDmbNUUDVofPbDYlvTpnNOS20Jh+8DXkBp0bHOhEQd1kJnwepRrOpbVn0\n0ASUI63AjnVVY1H5K9LaatOhT4xBzjE8KqzDFEVgn0nFkeRG8lbyik35riIw\ngMBuynI6wk129xfbK9hFmgwMBAbifC3iB7Tt/MinIx/lusDT1coKm4kadItv\ntRMc3hU7l5/rarewwThu7VslDxEQorvnSvmzZ2tc/ymG02kulyYYztOfQ8Jl\nou6O0yR1vk3F4JFzkjf70f2TrBY+o6bYSoz5zUgXiP8QMkZ6yyCdq+0PbI6r\n9l7np4PT2k7xtQF7MQkHFcrYU++dfIxxldLsk/Oh8U2WmPixf9T4nRPuP2Fj\nUoHryjVfXpqPNoLyFrvYUq/L95UMqkloquvstXcuhSlwLHllMrtrdt3kyn9X\n5FR4t/agxMo9qfQqxfDQEU7CBLPt08MvOZ8D0Tn83L0A5+HWzpLL0QVLx5JN\noULyZZGWTNoqQ1bdFZCDVL/5Qht26YKFjTw0DIbhXRRU0Dba1iGZ972h3Agp\npEg2Awb5Jeu7sriXQK9BsKhtY5+a89jRfZzAT+LPcbR+86zZ3SQZcq+r6/y7\npmjO\r\n=af4+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH99rojVNLnJ5JfNgrfzw0lcY/Wm83WVpflIPUwztCI/AiEAnORCj5fpNUm1UKSQ2PXllc+G9FW7FZnvdvzmX6zakAI="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.2.0-unstable_1550386716911_0.6702232886026276"},"_hasShrinkwrap":false},"2.2.0":{"name":"react-modelx","version":"2.2.0","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.12.1"},"peerDependencies":{"react":"^16.8.0","react-dom":"^16.8.0"},"devDependencies":{"@types/node":"^10.12.21","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"73d5505b2ae78700b45d5a7360a1c9a63aceceff","_id":"react-modelx@2.2.0","_nodeVersion":"10.15.0","_npmVersion":"6.8.0","dist":{"integrity":"sha512-ezwptOXaYJ9uEUCQhmd7w9Z5ejQtd78MOoDNvQo1DjHO9RMkpcyeNHDREGS/brDx0fYKH8VlU8OUz+JpHRWhCA==","shasum":"b5fcee0fa31dbc43e46305e663824777b1a5048e","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.2.0.tgz","fileCount":11,"unpackedSize":42597,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcaQidCRA9TVsSAnZWagAALFsP/2kbSGns9967H/2rG/Z4\nNqjUY/GEUa0c7zlz4r2+n9LEUtRlV7tI1S0k5fQ+ny/ujmLNJgZMpMt73dC1\nxORBG/YitPaDe5savFbPwVlRJY0bmKRt7PtBYBkJjdUhReCcJ81hQmOaHOeR\nqI1+FS/qb3QSJPM9ccGo0J6RdsqHQd2TfHegR1FuEyGJkpYs/fcEQwTewvdd\n3+SyiJSKK6gflXNMij7a9xckj/NtuGycTcunH/0+eO1coDliBLfZpY8xcUu4\nylEEZaAZJjf+Hxi3xnMpyAc9T0nfsQxRfY6gQqwZCvde3ttcB/2d+98pJrlk\noxr2uYOh2+ptUc0/uPLU+eniOxfymH3RGdeHFcFeYX6rmz29VmI3fF/GE9+R\nWzhy3VYve8SqcaedVujLW6L0Z2Quzx7FVLuaBmOoh+1N8HsbG5igrhWhI4KE\nvltIZVkTypjG4DV0M17DNu+Aw1JlkGcEAfpruKjRuybXuZjKsyuB6FZrQhF2\n6LJCJaKtGhMCZ7YA9ucoNhs4npYiLvkD1vPdUTT3wiyXWQcvE+hx3vmftnGS\n2m71YGxjHtiNuX3m0b/FXITJ7GqLyROx//i78XNWk0Ngm56Zy4pOyuJmFNqF\nfFRPZ43gd8HmANTwR67LxENfsW0MFI6dIcSWsy5rCeg+CuAEWf2lXwTHmfXe\n1iID\r\n=fAqA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB+iu03ws8BhddxQr3DL+xDop050Y0LJTyTHIJCZDgAzAiBgWcw2gqLAf37YYamNB1QpvHjCzafCP+HlLuwkR7PtGg=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.2.0_1550387356950_0.31752150469815543"},"_hasShrinkwrap":false},"2.2.1":{"name":"react-modelx","version":"2.2.1","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.12.1","react":"^16.8.2","react-dom":"^16.8.2"},"peerDependencies":{"react":"^16.8.0","react-dom":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.5","@types/node":"^10.12.21","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","dotenv":"^6.2.0","jest":"^24.1.0","react-testing-library":"^5.8.0","ts-jest":"^23.10.5","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"0077660d3bf89ff1508496cf04516f536d769f88","_id":"react-modelx@2.2.1","_nodeVersion":"10.15.0","_npmVersion":"6.8.0","dist":{"integrity":"sha512-21UJbLu4vsySdG2sdTUlnM+OYK1Sx9LX7BXuYRYtH9rPa9eZwzgq1TcSQJiBQHhk2QhjTeRVLyq/viVEZ/0TWQ==","shasum":"0ca18a2eb6731ddfc2afe868d1f3f3dc3f8961e0","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.2.1.tgz","fileCount":12,"unpackedSize":45409,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJca5NrCRA9TVsSAnZWagAAHOcP/2i4YVkJoFe9BOEmanTZ\nyUJ4WXiIl7duBKBWkHkWMgq9MOyCqBLUt5QdDulN7k7HMKG5jJ2d2OVKqVTu\nPEpxuj8MALCSjmSqj7aTiesATMRnDPnFJAirhlxipJg2q9a4TmPt26JsR9jZ\nFTveEhtsqUIRQ6hsqcfWIBEQH7c9dvDsa3yOkWufzqNK2Jl/JvE4ZYlPpY0z\nPhKoi3Cl0eAlFT2BFAfZkfQRpUuuK+pQLVu2TuK0bvuREV8/MJgqMkQXCev4\nuBmcPJHjflMpqkUYCmqWld+ZmdtFWjwgBdZyyW2kAAdYlItz7a1hKcKuqKEM\n7QEDG/AGo5yjNsIOL/2cyohYfZ5uTas/4+jen4h30xmShNDD9QAfZNM68UEO\nzE4zlnkTVIQpO8EKgDlfOJVQPehaBWEWJ8mqqFEEZzawbOwDeim0Ix9N/Xc5\nviVovCTxI6YEGJ2diKGy3DrE2apkLCJoFZCYCn0yFa5+VJN+YZY24dU5LheT\nlqwHqd9CMZWwkTxoIPypRaw0EpUgZTTvT0hO1S4N0mhqNx+vV2R0Zy1CuzfV\nijUz1igByViGgpBnjA6Lzymkm4I2kDAeXPRXGptYPmo6rKxga8VAFjrDmQcN\npshv+K4dcIiB95NBFRV3YfoZrHr9cl6xrZQv3isgNzZm/JVL2vlf9loLhAfw\nkiM1\r\n=tigQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCUjE4PgFoYd9UoDnB+HoHk+lTshDXnvvYfjaAgku3UbAIgDr0EVYZExzf8n7ZslMF4t1GSS/CzX9kgU+k2QyOXOKU="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.2.1_1550553962791_0.5977993025620931"},"_hasShrinkwrap":false},"2.2.1-unstable":{"name":"react-modelx","version":"2.2.1-unstable","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.12.1","react":"^16.8.2","react-dom":"^16.8.2"},"peerDependencies":{"react":"^16.8.0","react-dom":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.5","@types/node":"^10.12.21","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","dotenv":"^6.2.0","jest":"^24.1.0","react-testing-library":"^5.8.0","ts-jest":"^23.10.5","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![downloads](https://img.shields.io/npm/dt/react-model.svg)](https://www.npmjs.com/package/react-model) [![Coverage Status](https://codecov.io/gh/byte-fe/react-model/branch/master/graph/badge.svg)](https://codecov.io/gh/byte-fe/react-model) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Quick Start\n\n[CodeSandbox: TodoMVC](https://codesandbox.io/s/moyxon99jx)\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Table of Contents\n\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React ^16.8.0 can use Hooks to connect the global store.\nThe actions return from useStore can invoke the dom changes.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\noptional solution on huge dataset (example: TodoList(10000+ Todos)):\n\n1. use useStore on the subComponents which need it.\n2. [use useStore with depActions and React.memo to prevent child components rerender frequently.](https://github.com/ArrayZoneYour/react-model-todomvc/blob/master/src/components/TodoItem.tsx)\n\n[Demo Repo](https://github.com/ArrayZoneYour/react-model-todomvc)\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\nNote: the getState method cannot invoke the dom changes automatically by itself.\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"d86acea22c8f308768054445b68e3b5071f3b4a2","_id":"react-modelx@2.2.1-unstable","_nodeVersion":"10.15.0","_npmVersion":"6.8.0","dist":{"integrity":"sha512-y2nEqZ4/lp4E2/EgjcZKegeM9ki1/9xN+8Irx7/36i2Sc32o3t6pFXr5Pc5Oi59OEQQem5NA5A86Rqdy36fMFw==","shasum":"6dc73eb333699a5fffc8dff7affeda43ce67bbe4","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.2.1-unstable.tgz","fileCount":12,"unpackedSize":45462,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJca5T0CRA9TVsSAnZWagAABj4P/1GSJPpen1QAjwj0X1uu\n1+6BV7NtkH0gkcdtkZ+yUjK/E8WattjKgOLTzKyyK1+xEJudjoSqtxIoujlk\nN1ar7dvriws1e0hdRim5LdjuuZpa3AjpYH9hC5Fd1mIn/0hnkxTuUD6AKVX2\njzQnk+cG4MY9Yt/p7K7uW1Hz90yk9SrDXCTNxdsl6p4ddzDj3zTfLhcdsQaX\nhlC4iDAK1fY9jhprxarNFU1Qeu3+zxXLkMPoRUWQoUeDK1+JviatcvzY/F3r\nYAhspKNsgd7lZvxYkwzxkU4bCF8JyN5aIiBmRZHBcBumEyBVxhqYov6+2VHw\nCIDRNmNZ95JJNeZ6uMzJYDaxznJvrWEDUQZ8qtBXrplM924DhpT0tsiOAyrt\n0vSm1D05q5BNJEbVYQe+xarz6qhh+omr4OxQcnTJE0wDE0iEvohpxtxgU/E/\nniALwVD8HoEZ8mYGumePfAnO6NTK0WO/q3q6M+IAW80nhP2/HXuP/JlftrpS\n1hLzJ96OVOHq/+Riftb7bQbgvJwcSwufyF0D+PDc2eEqNLepl8EYtFm1YWjW\n5qpo2LdE2RbDAr4jTLfVt3qVIz+Aphmlo4vG3T32xc5pYshv9C2iXvhrd33Q\nZgg/5b/90XuEXFUz59ScBK8PAcNVoLAHcQfWPVldX1u6AGzfpolNBcrENLPl\nBS15\r\n=AuQi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCTmibunjdl8DHQRCajSBWkhqRL4ZMDRkD6eJBL/PKHUgIhAONR8eEJVBNIO4DhqO6nmb4z15LszLDZvveWCtFMpO1r"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.2.1-unstable_1550554356276_0.291517561434695"},"_hasShrinkwrap":false},"2.2.1-beta":{"name":"react-modelx","version":"2.2.1-beta","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^1.12.1","react":"^16.8.2","react-dom":"^16.8.2"},"peerDependencies":{"react":"^16.8.0","react-dom":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.5","@types/node":"^10.12.21","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","dotenv":"^6.2.0","jest":"^24.1.0","react-testing-library":"^5.8.0","ts-jest":"^23.10.5","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"d86acea22c8f308768054445b68e3b5071f3b4a2","_id":"react-modelx@2.2.1-beta","_nodeVersion":"10.15.0","_npmVersion":"6.8.0","dist":{"integrity":"sha512-QrYeBKfP9j66F1kHyeShPTmtxBEgWtTF5KuLvwSIsUGt1yJ0BAqdl6oLoVGVgvOllldn0EfUq5CA/iX8LZFXIw==","shasum":"423561d992f4a68a59965866bd7c986ee6db4f8c","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.2.1-beta.tgz","fileCount":12,"unpackedSize":45458,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJca5XjCRA9TVsSAnZWagAA1/sP/R5QJoifMgYzys85/LVZ\n65VYMi/e9ick4ySSrond/0i8lCBVNmoS3TfYQj7EexsbYJM4XVejW/CHRKfT\ngMRujGkOZNdnZ0GFxYGD/e57G6WNZNFkQvPOp9g+5ie27UgTPrwJKGnHiaov\nErHA3HKVveZ/EM4D0Ok9uMpJaLR1JW9eOqtekhuswOjU0bOhA8pB/xNj6yL8\nYshRVZMsui5ibIPsZYjGKKYic3vcA1dIlGjGnw7pwMtTH6oI+1XAXEGsvN/d\nTxsrCXiv1P+VnhvLQ7mZzDTfGor3TFhGkalqdLmOChZ3yq/QmQUcsPoKDZ9W\nnUn1bj8BRq7dlB+xTjgzXPoE6hzi9yoSgJVtjyseigN7fxxOh2vYcKNO+ohz\niZsU+XJ0lanNH23XcPXgIU2IHqA5M1sh3Ei7qMUELkRB+LR5zrFJQLa94q3a\niZBrUBY6xLFYNZuJNsyZZn3zW9kFPZVqkzd2nx4zE0ctDr7wi9xIS2sIuYut\nF1nADRvuiRDGKU4XBYunik1UYNYCVvpz28TYhd5ZTSH5GaWKH+J9yr7Fh9Yh\nn45TU0u25L2qkch19npZr+pkQILQAGLH/oI2W737Wd98dAzuptJ8NaFuH9pT\nva3sFLJrH6yW58+jBuhRUWBynpG+FQjSgIe97n1ACZp0MG97h+7KtFufAadQ\nvpdn\r\n=mfe6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDjT3zNkT0wEZmkg/CuHaMIEOJrFhBovtPdz8SQdlIaMgIhAOMLTc+WMVcEEJ9R6MqNff+1QYCWKCKQXPeBXggFLEqc"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.2.1-beta_1550554594534_0.719963299132049"},"_hasShrinkwrap":false},"2.2.2-unstable.0":{"name":"react-modelx","version":"2.2.2-unstable.0","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0","react":"^16.8.2","react-dom":"^16.8.2"},"peerDependencies":{"react":"^16.8.0","react-dom":"^16.8.0"},"devDependencies":{"@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","dotenv":"^6.2.0","jest":"^24.1.0","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![Build Status](https://travis-ci.org/byte-fe/react-model.svg?branch=master)](https://travis-ci.org/byte-fe/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![downloads](https://img.shields.io/npm/dt/react-model.svg)](https://www.npmjs.com/package/react-model) [![Coverage Status](https://codecov.io/gh/byte-fe/react-model/branch/master/graph/badge.svg)](https://codecov.io/gh/byte-fe/react-model) [![Greenkeeper badge](https://badges.greenkeeper.io/byte-fe/react-model.svg)](https://greenkeeper.io/) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Quick Start\n\n[CodeSandbox: TodoMVC](https://codesandbox.io/s/moyxon99jx)\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Table of Contents\n\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React ^16.8.0 can use Hooks to connect the global store.\nThe actions return from useStore can invoke the dom changes.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\noptional solution on huge dataset (example: TodoList(10000+ Todos)):\n\n1. use useStore on the subComponents which need it.\n2. [use useStore with depActions and React.memo to prevent child components rerender frequently.](https://github.com/ArrayZoneYour/react-model-todomvc/blob/master/src/components/TodoItem.tsx)\n\n[Demo Repo](https://github.com/ArrayZoneYour/react-model-todomvc)\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\nNote: the getState method cannot invoke the dom changes automatically by itself.\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"9c27922a9f7bea3a23ef6b549847dabda12cc66f","_id":"react-modelx@2.2.2-unstable.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-pZykxL9FxzFfq4Sq4RbJY2+IZJLcH9z9pO7udLDrMaMlHmYGJMayOIwD/zLW7SqzcuHGI/e1UxKSg2TC8W7IRA==","shasum":"9b40ee9e8d00c2006b33aad0df1670c37a84b705","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.2.2-unstable.0.tgz","fileCount":12,"unpackedSize":46282,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcb69QCRA9TVsSAnZWagAAtEsP/jOgUE/2rz+wklyCSXkJ\nVMrx9jL7J2AflkARiRVuysnWNKOMT531BsC+BW5vRHfTF2QN3sjmF1MonGP2\nXdrhVUMJnogMU4/7Uy1ufBPc1UbyV6e8lu+Q1j5M17lO1f+dcbg6Yw4ij6cS\nMA3P+FoaGT24EeBCZjW9UpcIbQn+zu2mtvNa6URPaEGW5KxyCYqye1JXdSaZ\ntPVouBS/CEJQxfHHukXi9X6y22NrNEUSOlfQF80whh/nT+WhETLwTdzGlLcW\nUQu94NXrg3iqVpb/NVgpM2K9L7e4Rj3NV5qsn91VUZYWWrSPPJgfxDCV8jMj\nfSM0BIt/gPSrgtwuw/RKrhcyT1eoO1B3DnVtL5x32GPMnR40zhAc0pifKPLX\nO2qmShGBTAGD46La/6hOwcZ6/Vu+vkVSC4hdBmGmGuSBaGvnghc4wahasoiA\ngOmdA19OspxZPjy5WLfemZx9uRD8tSj6qtzozjWB6OCTre7ueGojRsdIMXFc\nSt+a0Ry9vGu51lgfrDqN3uHGY607E9s6EP48Yu6EVMcNsMWUJkfBAfe+jV6R\nj5p5K/1m86rVFNuyWpIXFudyz+Ja1T7lyGDAeMR/0GO280PUPF54rgGVR4aj\n6dJ9bjNSCuocv5JH9fKCc+th5lwd5blJ5PPPQuQvj511vToPBk6QnL8eOhhi\nc7zY\r\n=Er7g\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEQN6RV4E+AKJmr17SvdEDvGATWh7MNRq/FJ3eL9+BZcAiAgPK0bh4FIz2xQDpLGEoIbZSRuspxhgD1s38CcOGW6ww=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.2.2-unstable.0_1550823247859_0.9803846379571519"},"_hasShrinkwrap":false},"2.2.2-unstable.1":{"name":"react-modelx","version":"2.2.2-unstable.1","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","dotenv":"^6.2.0","jest":"^24.1.0","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![Build Status](https://travis-ci.org/byte-fe/react-model.svg?branch=master)](https://travis-ci.org/byte-fe/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![downloads](https://img.shields.io/npm/dt/react-model.svg)](https://www.npmjs.com/package/react-model) [![Coverage Status](https://codecov.io/gh/byte-fe/react-model/branch/master/graph/badge.svg)](https://codecov.io/gh/byte-fe/react-model) [![Greenkeeper badge](https://badges.greenkeeper.io/byte-fe/react-model.svg)](https://greenkeeper.io/) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Quick Start\n\n[CodeSandbox: TodoMVC](https://codesandbox.io/s/moyxon99jx)\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Table of Contents\n\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React ^16.8.0 can use Hooks to connect the global store.\nThe actions return from useStore can invoke the dom changes.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\noptional solution on huge dataset (example: TodoList(10000+ Todos)):\n\n1. use useStore on the subComponents which need it.\n2. [use useStore with depActions and React.memo to prevent child components rerender frequently.](https://github.com/ArrayZoneYour/react-model-todomvc/blob/master/src/components/TodoItem.tsx)\n\n[Demo Repo](https://github.com/ArrayZoneYour/react-model-todomvc)\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\nNote: the getState method cannot invoke the dom changes automatically by itself.\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"9c27922a9f7bea3a23ef6b549847dabda12cc66f","_id":"react-modelx@2.2.2-unstable.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-NXUP2CdZ+7h4ArOdRyHcF5oXuDVIy57S2+lRi4XDa3/dJbJioZPM1rhrkvRcOb1deQ68KxeJoEsIg7ly+YUjsg==","shasum":"390deeb2769b05f1157480eab127e40e4f8caedf","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.2.2-unstable.1.tgz","fileCount":12,"unpackedSize":47010,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcb7mACRA9TVsSAnZWagAAVlIQAJ6KA0Ngyv1OESOSC7aM\neOusnnH/+ezYmNNR50SmfpYlq99oymmtd+qnImNFrvY2DqYIi/BmZoqaj5pc\nKRT1F+dEgatx1X0LOr+ylHlktVNb+B5Wh5tmQRM1Uy7qRzVd3TFKk1il2l8Q\nCOHXwPsj9JoldTUY00NY0dBrLBDn7xbwf+JrjEqBlj4471FzoiVNCtWnXLpO\nn2pw0JB4wQyWHBRWf4Ok9iR6RnaJqHsJMULMO9JYSxplRAB8uzBQfI51+C+q\n9N/PpFFZdWgAUKmB57di1Lzrgii/oH7oCfqXIpRrhDCkKXpBVRgq5GYca3qL\nB9r8cKlMHo7egc5JflEo/eE/ZVwDalfTV55tLNDeeXAAL8L2BmDKLWI0RsnI\ntcte9y+burpAYfAPth3YwuctfGI8ZB1pOh9Ibq0p7kafJnslwZvZlKxW8HBP\nlS59SXuNLXoibt3MSGhPTULOZnaT/2jd6jFxAS+h5tJVhMZwZWolobScdXYs\ng6tXcPI1tTKqU9j1IKW60PaGlIA5jYiE4E+wvK7cBU719gDVXSyPcYjtJYK6\nqmj31u9vlwp0vJDew566/blePcOGovxbDV+aVak2+bH8BbvDN+cdbaUX9lTe\nafCnveORUIeJoP4QscLmrwEfbW2hYFtq7TM6r4/1NKR9Z6blrj/IdVEtkwmb\n0hAT\r\n=psRG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHO9G5QoyK/w+5RrniVZMWboCXYWawzufkwzqBGleBf2AiEAhF8B3Kc83n69L0wqIKIU7F1YNAEVI51cMFKIovsetY0="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.2.2-unstable.1_1550825856133_0.2149539616103373"},"_hasShrinkwrap":false},"2.2.2-unstable.2":{"name":"react-modelx","version":"2.2.2-unstable.2","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","dotenv":"^6.2.0","jest":"^24.1.0","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![Build Status](https://travis-ci.org/byte-fe/react-model.svg?branch=master)](https://travis-ci.org/byte-fe/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![downloads](https://img.shields.io/npm/dt/react-model.svg)](https://www.npmjs.com/package/react-model) [![Coverage Status](https://codecov.io/gh/byte-fe/react-model/branch/master/graph/badge.svg)](https://codecov.io/gh/byte-fe/react-model) [![Greenkeeper badge](https://badges.greenkeeper.io/byte-fe/react-model.svg)](https://greenkeeper.io/) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Quick Start\n\n[CodeSandbox: TodoMVC](https://codesandbox.io/s/moyxon99jx)\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Table of Contents\n\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React ^16.8.0 can use Hooks to connect the global store.\nThe actions return from useStore can invoke the dom changes.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\noptional solution on huge dataset (example: TodoList(10000+ Todos)):\n\n1. use useStore on the subComponents which need it.\n2. [use useStore with depActions and React.memo to prevent child components rerender frequently.](https://github.com/ArrayZoneYour/react-model-todomvc/blob/master/src/components/TodoItem.tsx)\n\n[Demo Repo](https://github.com/ArrayZoneYour/react-model-todomvc)\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\nNote: the getState method cannot invoke the dom changes automatically by itself.\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"9c27922a9f7bea3a23ef6b549847dabda12cc66f","_id":"react-modelx@2.2.2-unstable.2","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-R1t5L6esWmVmXaAmxDmFSY3r0mX9nohOOTZ4UOHV/wFuXWN0w0gX/VKeyF+h3kXfJFJVsMj6F0mXViHcaDNhyw==","shasum":"c18e931114000d7960415db87f92ba51e19d342a","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.2.2-unstable.2.tgz","fileCount":12,"unpackedSize":46246,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcb7qtCRA9TVsSAnZWagAAkPwP/0kA6iGPjGSkcIvsbbQc\niydvqIpIlEPN2iARZMIZ+OszyyHeVyGQnad10RXhOa4gz99TUwcAZKN202vr\nSC/JOXT927cMeWJ0GeBeLhxu0n2wffEYYWGkTUB6V5fKc4oz9k5STvcup0+p\n/I0efSa2ZJuAFwS8epL1L33K2EP977Z6kY5zRgu6SBXT0lfvDrKk36A2bc6H\n/GQ2gVda2QuImWKf5qiet4UfgzVfXRt8rv6AdvNBj5irVyhrscR4tpPC1/qo\nrkfdGUizpaMwIwEy9XVCwq9rNI+EyD79Pb6vJ4vSIX1nbh9RkcaIgwVjMv8C\nk7jftTqeuD4S/JB37KJf1Uofy7PPGOiqdlCJZpcTQexSDd5FQm/loR0XZ8oI\nX19zJjOcuPjIw+53TMgsb0EaQ/Pk8fjyZgGHVI1Oj95tmGKJ1bhcBDlCNHSY\nDut3/rLQDRJryc1CkaNeYe9tBSveo1JRjj3a26EWYi7UOUD0aPOcyUzuSnqe\nFJ4+SX7+4GPFN0Dr5c+5KviL51L3vhItwe0c2oRm+lqIcayKLyMaqi/ciroc\nkSnZTg+E6IHXcmq0+6WHA18p9QoXAMi7OQcwjL2z2Ddr28eMdNmsR8Tnrbnj\ncZGjx3yAs6gzBunoDG9XCm9hJVl1zflpnasbE3cf4zP4tgyYwgdLIpOEAgUP\nfH6i\r\n=zUVo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCwNjUD+nOrN37o3mD37akbp2rKuot2E4uPWuVxZ8or7QIgJM0zw2t8SLPtKWqrep/4S30x+ONTRJsHNr1R41tyVJs="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.2.2-unstable.2_1550826156784_0.8626332170915763"},"_hasShrinkwrap":false},"2.2.2":{"name":"react-modelx","version":"2.2.2","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"npx git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","dotenv":"^6.2.0","jest":"^24.1.0","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"27643e6bbd858f5f9d1ee00bacee121544987af1","_id":"react-modelx@2.2.2","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-SUtqsnni752WpYCOEwduOUmoGepsWZtxgznrKVrQLFuKxiju4Tyc7a8myMGRJK9DTeMlm7WkOd75g/bd8RjAQw==","shasum":"6b6723ab783716165c50ad607ba7f22a80263a97","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.2.2.tgz","fileCount":12,"unpackedSize":46324,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcb9cKCRA9TVsSAnZWagAAUDAP/A0VZhYSVuLwY3r9lqtK\n6PGfgRmYdn9SYyP0rTECgg7W9Qru9nxqBBiQQGGywDo9V8c8SF1Ji6GRmIAu\n1wFnYbLDn35dXVfu+jfbJe3mILB7Jfsr/XlbMfdfPv+1FZPup294sD7DnTw3\nNtOY3msmvvwqZaC36630GWvsaSPwJrDU0w8VTowR/LPJ/Py/Dkw12HjPBg1b\neyTQ553+CJ5benBMHbcJc1POrsXzv2rIAY+OjrQevm4fBCsi3boHzIsH8hJG\nw44HHM81zXgT/Ev2MDWWyBbp68xGCNuT322UI/Y+CuKhiIxMULxT2lTc2M8U\nFppoKH3H+0qWwwykS7VvndbRyRBzPR5uMTbW0nxXBc3t75TcUhuntTVBdoOV\ne1vNJ1PfY0Pbuibj+KCK8pE8AkIwNunUa+hZdHH66ifCj5JPpBHRWKDPCUL/\nhYJJJKpL7L71sl8siwvqg7rWEaL5QmodWWB6MF6Ucmxsu+CzuSghWUlFSfQM\njZUrlg0zYCC+ACGdmXcCdPshR3QO/33yS922OFXQ+tUuQNSvzMrYxoqcQkye\nourJskCxAMVxNPVDS8T2TwE+2TFKEmh43INfV/Dx7SSE4wjsNvJP1bCGhgFQ\n1dpbG3jVzOf27NXM5X2ActIo1F3wKPbylQPzHg3g95TyXlzNe6RUmJOwbct8\nMdqe\r\n=LHN1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBmhPwiAigvk/mI4BKUuRgIjSpGpWeIq1yJNcLpa1zw1AiBgXjlrIW8VBGK3zu5JuxPgJ6wYzlNzRWa0RJ2Fh9hYDQ=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.2.2_1550833417938_0.28639654882882914"},"_hasShrinkwrap":false},"2.3.0":{"name":"react-modelx","version":"2.3.0","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"npx git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","dotenv":"^6.2.0","jest":"^24.1.0","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![Build Status](https://travis-ci.org/byte-fe/react-model.svg?branch=master)](https://travis-ci.org/byte-fe/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![downloads](https://img.shields.io/npm/dt/react-model.svg)](https://www.npmjs.com/package/react-model) [![Coverage Status](https://codecov.io/gh/byte-fe/react-model/branch/master/graph/badge.svg)](https://codecov.io/gh/byte-fe/react-model) [![Greenkeeper badge](https://badges.greenkeeper.io/byte-fe/react-model.svg)](https://greenkeeper.io/) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Quick Start\n\n[CodeSandbox: TodoMVC](https://codesandbox.io/s/moyxon99jx)\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Table of Contents\n\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React ^16.8.0 can use Hooks to connect the global store.\nThe actions return from useStore can invoke the dom changes.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\noptional solution on huge dataset (example: TodoList(10000+ Todos)):\n\n1. use useStore on the subComponents which need it.\n2. [use useStore with depActions and React.memo to prevent child components rerender frequently.](https://github.com/ArrayZoneYour/react-model-todomvc/blob/master/src/components/TodoItem.tsx)\n\n[Demo Repo](https://github.com/ArrayZoneYour/react-model-todomvc)\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\nNote: the getState method cannot invoke the dom changes automatically by itself.\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"85753f105dc4f638192062f5ea8ee5d4cc89932d","_id":"react-modelx@2.3.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-UOhTZNpyL9VkHw6Wy6nVyUiMMIwLRD9BWVuM162tdvHszRcXyuajskV+6l0Nq6F5v/oaEgqhZICaoFuBp3Ty8Q==","shasum":"6c2e03252c1d6864005121128b077c5ac1326cab","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.3.0.tgz","fileCount":12,"unpackedSize":45968,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcc6+nCRA9TVsSAnZWagAA18YP/jM7H+3pMCrC+jWdIgkJ\nTKhcM4MotoQ1X1eiNuPQ+YfGqwJloMKXvfseMb0RSBmu9AKRL0xs31GQghS2\nxQ3OZ/x8GaJp8Kjg7YbFkaP+Xjh+3cybD750/UiPW3FKhRTFqaXoAwNChzGR\nqdXpIE2ofu+J24ujadCp9TgCpddtIFxO4pNqyrnv4L7mbj8xqp/5tq7AvcFT\nhHAvnIBEvbmQdsgu/yg/ILA5sIQlRHlShPKVXHmuMS73cYwkyR/Bq/GM9PAq\ngEZLGA28DUjWxpjdji72Xbd2r3kAPW18h0O6rBP8vqgu724rHN4wKLMyCK0U\nrlOQGldC1adYkejatklbApy9hSpezRgmCOqaaB3gsCbnyzy34iwMLLTe5Uuu\n1UzGmK9gn2JKQCL5VUrmc+jBitkbV2E2QEr1FgQr7bv2ah9d3ydqOmZT4kJr\nXx3SuR3OBsmLb6QSimfqt5Rk9An6GmDm+NCS59/t/7GBCd8LmFyLOcvEq5oc\n+b7nj31Qyj2Esfk2akeHz/o3AzMoIFtvhbRk3NjEZUbLE8x9bfyMQABAWvuz\n75r4aA1JTl+OAzNbi//TFX6rcZSFLJ5eiZ6/AUSDW/ZqrBVFNSq8reVrKK4f\nOuiSYNg8l4rQ545zF6aNdCzYgXnBHR8t6uiudGPEcxo5jFC5FAs2KJrxv5Rw\nUiww\r\n=ao6v\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHY3OMmBInWPEG+eFUVv2dCdBcwKGyxhRDtxNZmHYIPVAiBdAdX5cnnfTSrzacmiS+bpTVlPEDzChLr/ykIUQeddPQ=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.3.0_1551085478575_0.3625684591644931"},"_hasShrinkwrap":false},"2.3.0-unstable":{"name":"react-modelx","version":"2.3.0-unstable","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"npx git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","dotenv":"^6.2.0","jest":"^24.1.0","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![Build Status](https://travis-ci.org/byte-fe/react-model.svg?branch=master)](https://travis-ci.org/byte-fe/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![downloads](https://img.shields.io/npm/dt/react-model.svg)](https://www.npmjs.com/package/react-model) [![Coverage Status](https://codecov.io/gh/byte-fe/react-model/branch/master/graph/badge.svg)](https://codecov.io/gh/byte-fe/react-model) [![Greenkeeper badge](https://badges.greenkeeper.io/byte-fe/react-model.svg)](https://greenkeeper.io/) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Hooks Api\n\n👬 Fully TypeScript Support\n\n📦 gzip bundle < 2KB with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n---\n\n## Quick Start\n\n[CodeSandbox: TodoMVC](https://codesandbox.io/s/moyxon99jx)\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Table of Contents\n\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )](#other-concept-required-by-class-component--not-first-class-only-support-on-csr-welcome-to-pr-)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React ^16.8.0 can use Hooks to connect the global store.\nThe actions return from useStore can invoke the dom changes.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\noptional solution on huge dataset (example: TodoList(10000+ Todos)):\n\n1. use useStore on the subComponents which need it.\n2. [use useStore with depActions and React.memo to prevent child components rerender frequently.](https://github.com/ArrayZoneYour/react-model-todomvc/blob/master/src/components/TodoItem.tsx)\n\n[Demo Repo](https://github.com/ArrayZoneYour/react-model-todomvc)\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\nTo solve it, we provide a way to get the current state of model: getState\n\nNote: the getState method cannot invoke the dom changes automatically by itself.\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component ( Not First Class, ONLY SUPPORT ON CSR, Welcome to PR )\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"85753f105dc4f638192062f5ea8ee5d4cc89932d","_id":"react-modelx@2.3.0-unstable","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-kMpNAN08Q4ATPbRmk0Sv2t6KXeoNf6JtaFwYOF8Vz0RVQKHBVqnQ4oujXIenk1K8I2WjDEFO7Vq3DA9RzHFJ3A==","shasum":"de7f571614bfbca04cdfb26f3ffe5ec0db488850","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.3.0-unstable.tgz","fileCount":12,"unpackedSize":45977,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcc6+5CRA9TVsSAnZWagAA+3UP+gJqH/emarhcOTwdFPeG\nZJsDWIlj90mxJVzUUb/V3V0wz0pS0OczetnwlSK2OPNQmal+0BBdASA1nkQx\nOf1TOJbzVKBhM6XAJXxPdWgIR/s0eV0EVtZAxe/joaW+Ib/+tdwHSBSOWJp8\nIdEcXc+1ABf/gWfzxAc2hxG/Y3AO7IA65eVK1PCYZlcTCFuYr8KeBoCuK1OB\niAnqMCtgsQ7aaEzNIg/lP4Filqc3xzSTOt09TvBEVlA6b7eMx0MJfnkUgkzu\nf29lWhh1P32oxrNdiNlFo4ffJ/uVxlJDDsQTBOyoIU9HqfKEA2ZlhHk6zBNi\nxtm19j3dLlsm9EGqQAV4OEaFvIB0wsWRXrrThsBBdRmkFEUG6lLxk1MfwOVd\nWvx0qxzUnXT5FvrsCOzXVmXwlBv5KC+Rxd5HrywLGtkVZ9CEkkHN+GpbLtab\nFnkdvPkTictAtdlIyu0NKL5bNtGXrp68kcbCsGXJ2Q7+xzzmnbfSP1QwcuXK\n1Q1xRr0wkQcis1NY2bh6s2tvbVPPd/nXrflcw2mNXoLXrSb0NMYP/zar6l3D\nxO1PnmhmQpq2MKWpdTfx+GVXJ5IctsYK83O84QbJXZnKXYQtQ5y7TXto0UkB\nHTJCtTmo4WJoc266y+q9lZ6gQP2WyuOJjKclxJZNM8Vs9Uo3sH7yNrHt8tbr\nQcJ4\r\n=JiTD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAUMIrz3XFxYNYH4//VM3Dl/oIeq23dRx/leidHq+oVOAiAFTSmBnxCn0SznsIv6Tz9XM7TDCKze1tHIKFMa5LZUCw=="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.3.0-unstable_1551085496501_0.45886595454098145"},"_hasShrinkwrap":false},"2.3.1":{"name":"react-modelx","version":"2.3.1","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"npx git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","dotenv":"^6.2.0","jest":"^24.1.0","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"16f3605d2dc805d494f29911749535955403b9ce","_id":"react-modelx@2.3.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-MukoEjwUwMJoT1p9oYFPMwShhQYNA1qimuQ/7V1NBR12zZGhdQdFCnm3wwDnm1ruapJ8MEsD1nsVp5xbtUorDQ==","shasum":"6a9a10546e152b2475e988a47fe275d3558e5b44","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.3.1.tgz","fileCount":12,"unpackedSize":46730,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcdNCkCRA9TVsSAnZWagAAAH4P/iQR2h0IOD5JpAWiKV+L\nim0BgBVw/1jI9EO/0Swoe0gqYGuCewSbfQUUuc91y1S0eoSkXYqPoXevjKBx\nxn8RuufwiNGjUhatbX/J5HdGQqxRFXR+PMRZ8+QbvJeF0b4ZO31mKyXD8VjT\nKVZulHNTWFlU7iGQ5umne7x3mLNV84rZfugcp1d2uFM1IvhO6namn6fGRm79\nxTSVOhAzzOBhNC/R86HMWwbh8MO9Xrl+VS5rYBtpuLhVTp7qCwBwDNA93rDG\nbd7iDTtyMbdjZdtdcRdBOGz+rzi6CBNPFCixV5a0ctcjySrAg7xSJHS8sjIh\nMQdi6kEjGtFjp5EAdycE+n7k5QnuYwktCa6YRMcG8MPGF4aPmiJ4p7A7ksDC\nCBpm4z3xD9WS2RulvQG+8dALFG2jHbS85RJBEREy11esHm5qE8/ux1IC82eO\nqlltTv2rL1WXw1R0J+bpeItxVMKkEQ60+BcXzowu+0hdBWI3ooZGplUGxTJa\nIkJJm+PHBbB/DwQUrysQM8AiQHzGpu3vWomqeWjTKGjppYqzgU4Om/i+ENgw\nJ6Hybg4gsiAxSgENZMUm0gMtMQbCL8NkmWWkeJKmIrjgPJY4qor3RZuumWcV\nMpbl4zreNDJgB6VyiOZpkJvEasbKv9r6oPxA+8cTQ9JsKJLRq1Mh0yRI2H3D\ncVNk\r\n=9TaQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBvGrKpvBlKHNaIflKSdQ0/4xs50XTdJoVRwcyTJ93WqAiEAhQz5hhAQf3EmI4kSrvU32OBue7SXlJOZpVw0mNGD35s="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.3.1_1551159459765_0.6736947348982487"},"_hasShrinkwrap":false},"2.3.2":{"name":"react-modelx","version":"2.3.2","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"npx git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","dotenv":"^6.2.0","jest":"^24.1.0","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"2cb6c0e8bd0bc58b160f70b60b8ac308c858657f","_id":"react-modelx@2.3.2","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-iXt6S6voD0mSlYSGVYsBJmZkl+LsA7A1oPEGMsG4vmisuzfNkyT8ysD0Z4Mwk99h7r3UODw54RA37rgP3GjR3A==","shasum":"73554c134a275ca0f2fdfe89c86aeec2c518915b","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.3.2.tgz","fileCount":12,"unpackedSize":46861,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJceNYcCRA9TVsSAnZWagAA+VYP/j+DJ6NRzw2xfHwECn+R\njhwl15JwnFWC3bvUTdBzxnW54IiNg0zI3tCyjnjNSz705P8cl5q1HhemSYpe\nebTg72hRl7nN615v6N1qJ1KuJNaAEv0wTXTVe50+GrgtICnKeUEaAM9VYWDg\nPT2WtBfYjsbvQImLuUyv4ZepNvETyrQ/dpAlBzChcMWU71GUpiy7s3FMlNbb\nwowq+ELrQ7f3SRMyukIJ6AsWt9FtnghZYnulCUgHJRiGJy/6Mki+lxd6+Zop\nNBJpl7HS2tM1ZCEH7hCAXAAzXfk1eY7TStXCl/slNI+IiA3gn0WL5YiHs2P4\nl2G5xoFlPdxUUbKBVA7n9bF75X6cb2hGHT/3OlGnnM8am9rlHz4LYN7bP5ir\njMZUKzcE/OR0QZSOfNfSKC7JKnq5hDfXJtVrQwCH56HH2tCLbPYYtpvsUnG1\nl4SOpoKygmO7toBEoXpH1pcQghr6g53HhAHJzRIU4Z2oq1O42XXIfDSZN/6R\nh8Xb0wH0Tok0YoygM6BC6tS36Gu9cj8gJjmeoGzEYGCWTIv5Eut4AoaUwwWx\ngEdinUGwvqcK4ub3/IUsoTSMCIPmnDSe6H5bYzSDq1mgmeW0wMtbZopQV5hO\njgaHiNMkhB54Qibk5bAEj+e1BYDcDim3SC8ab03S/fSMG+hZgpZJIu3rxeX4\nrccj\r\n=8skK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD5Y3j2cBNmZDq7RHD+IYNWaqxhNKaJ72mJcoxvhYa6PgIgY1bXfmk6qyknNuEveIG2D7fgOsrcP57U0bR48fsF4EU="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.3.2_1551423003781_0.9248119823144372"},"_hasShrinkwrap":false},"2.4.0":{"name":"react-modelx","version":"2.4.0","description":"The State management library for React","main":"./dist/react-model.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"npx git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","dotenv":"^6.2.0","jest":"^24.1.0","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","gitHead":"a9420462d2a94e35a572937ccebfbd2fa8ee50e4","_id":"react-modelx@2.4.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-bKwgOE8PUwZJO8y/taG51IQxy/SCDAqQD/w+EbspyuBqzum1KquDWFK36mvyQw0J7X59igUzBcR4gxTnPyfX/g==","shasum":"6fd9a01c60529195131faf8c7d140f322f8632d2","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.4.0.tgz","fileCount":12,"unpackedSize":51194,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcgP76CRA9TVsSAnZWagAArowQAIpH0Quq+f/qM5ags4QI\nheAbGxsYttnBlRGMd+V1OXeoJvlLkcMAcnWSYIMvSi9MuaTO0oBRtZdL4gCR\nH2LGGRdNWf+Cqgxq5gWl+AoFXnZy4n/uLzf+Q4OpsEXlatNc7IrPihWQonz6\ngQtXKNgikf7ZP+ulqGBp/zlDLQCw/5wE3EXz7xPkjK5HbE8ba1pUFLBNsiOY\nay6dFpChe1nC61CRxruthzIO5LMVzjk+Ejp4qxdPCiCNtd+tXxJF+v68u7Ft\nAtfyNTe9qUpZJesxDNQAxgmhJzUl2PAjj+17VEsMznUlZcK9/A1vSD/T/ci9\nEBgQNRyyNuAe7owk5aSOkFk1bCxvsjCg/Rq8xwhSR8KNnkC4aYZ50LQ2alNS\nffxIoS+B69B4UnHCbcBwPqczBuuC1ZI4OpRBvxEO4RB5ei2i1Sb0BG+KKSz6\nruC84I0FF47LD92S6CjyhmiIfFB+Y4jMYG5/da+m3qoFcvlY3PdBmWyCQ4DV\noxsc4WdIqdp5DQSjgifww1mwSSqB3e+98vpvZDHx4Ge4gzYVBg7/NyctS/43\nXls5VxfYr42tS9kYjsTRWDQXJ/nf0or6mhVNeGCHFlCxM91An8fzZ09Bgbe/\nEIsZ6xIMVYyAsRjaurM9sp5jfKpi5UT0pmdRUnWptrnsSSflOpzocGS9GNY8\nSpoH\r\n=Q4SH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQClEVX9dNdRXM38FERqlWylPXepb2Z3ETM+JtRZ+znFjwIgemWRuZauCEcezVc8HhWbe6K1JIp7lv8xBvlLqHg6v9Q="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.4.0_1551957753428_0.8469521212591713"},"_hasShrinkwrap":false},"2.4.1-unstable":{"name":"react-modelx","version":"2.4.1-unstable","description":"The State management library for React","main":"./dist/react-model.js","module":"./dist/react-model.mjs","umd:main":"./dist/react-model.umd.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@commitlint/cli":"^7.5.2","@commitlint/config-conventional":"^7.5.0","@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","commitizen":"^3.0.7","cz-conventional-changelog":"^2.1.0","dotenv":"^6.2.0","husky":"^1.3.1","jest":"^24.1.0","prettier":"^1.16.4","react":"^16.8.4","react-dom":"^16.8.4","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"husky":{"hooks":{"commit-msg":"commitlint -E HUSKY_GIT_PARAMS"}},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![minified size](https://badgen.net/bundlephobia/min/react)](https://bundlephobia.com/result?p=react-model) [![Build Status](https://travis-ci.org/byte-fe/react-model.svg?branch=master)](https://travis-ci.org/byte-fe/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![downloads](https://img.shields.io/npm/dt/react-model.svg)](https://www.npmjs.com/package/react-model) [![Coverage Status](https://codecov.io/gh/byte-fe/react-model/branch/master/graph/badge.svg)](https://codecov.io/gh/byte-fe/react-model) [![Greenkeeper badge](https://badges.greenkeeper.io/byte-fe/react-model.svg)](https://greenkeeper.io/) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Both Class and Hooks Api\n\n⚔ Fully TypeScript Support\n\n📦 built with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n☂️ 100% test coverage, safe on production\n\n---\n\n## Quick Start\n\n[CodeSandbox: TodoMVC](https://codesandbox.io/s/moyxon99jx)\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Table of Contents\n\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n  - [getActions](#getactions)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component](#other-concept-required-by-class-component)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState, getActions } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React ^16.8.0 can use Hooks to connect the global store.\nThe actions return from useStore can invoke the dom changes.\n\nThe execution of actions returned by useStore will invoke the rerender of current component first.\n\nIt's the only difference between the actions returned by useStore and getActions now.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\noptional solution on huge dataset (example: TodoList(10000+ Todos)):\n\n1. use useStore on the subComponents which need it.\n2. [use useStore with depActions and React.memo to prevent child components rerender frequently.](https://github.com/ArrayZoneYour/react-model-todomvc/blob/master/src/components/TodoItem.tsx)\n\n[Demo Repo](https://github.com/ArrayZoneYour/react-model-todomvc)\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\n\nTo solve it, we provide a way to get the current state of model: getState\n\nNote: the getState method cannot invoke the dom changes automatically by itself.\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getActions\n\nYou can call other models' actions with getActions api\n\ngetActions can be used in both class components and functional components.\n\n```js\nimport { getActions } from './index.model'\n\nconst sharedActions = getActions('Shared')\nconst counterActions = getActions('Counter')\n\nconst model = {\n  state: {},\n  actions: {\n    crossModelCall: () => {\n      sharedActions.changeTheme('dark')\n      counterActions.increment(9)\n    }\n  }\n}\n\nexport default model\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nUsing function as return value can make your code cleaner when you modify the deep nested value.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"c2d6cf738316899122aa23dd5db0a85dd5db531e","_id":"react-modelx@2.4.1-unstable","_nodeVersion":"11.11.0","_npmVersion":"6.7.0","dist":{"integrity":"sha512-SB6cwKslK/PWhCLupoI3JBF2FIqApP6YeCNVYJg8IUgnV33Jdqi7EnLCospHGnm/bDSSDrULmNrc9vM2vwtXdw==","shasum":"14d32df9e38945ee28f2f64207c29650ce46142c","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.4.1-unstable.tgz","fileCount":14,"unpackedSize":54186,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJchmqcCRA9TVsSAnZWagAA1wEQAI1sztj3SkTc+qGS5M2u\nd1Ao+QRD3A3/iEctR/X9t705iyE0KQPhnotbHpJW0Qp3JQ4sHKw/qNStncKb\nmnj9BeVfPUM4W2Y66I2eESe6t12gploDijn2hPzogB1980VmhPpsxrW8FEu7\nafyuFFBnn8E7HH4sFbM4Z8LLPN3T2DkwQvvvXL3YT3w26bWjUxX4GiCBGrWi\n5KkVPWPnL1SAqcXAA0BtABz2DVs0AbFCQQ9lqzYu5IeeoopqFVDju4ysPIkk\n71bC/A1cloAVSvyfiAwsGI89KczbDyaZorb6KOCaHQR55Ko+rsAGm6RBClXD\nth2X/2FpVJWQ212FIqgDDj5gmYKAlvyFPQ+0oqzQ01V64Pdid7aulwSiArdV\nvYDr7rLSq1liVLRDn+pjXOAkHp9iI55rMLukAL1Pd2hcfBlaS+m6MrADzqJD\naopu9N05cxhrLAr32K/W0xdQIp7G6LGHw3g2xXCOsEOr0/53ZeghUrppPNMp\nJ31dHuL3z/CFfR2HH1qawAOdtBaPwU8X6r/dls8YF+df6b5ujoGCt8Jxfar2\n7Avo0AjvnmdFVkYYL5FZ63ilGIKsRpI1uIXbLAvjYmSAWpks2qKTUBS8vlF0\nOel1OtcJ36h5tVNrHM1mM/EFz9U4A3OvfqydeEpeELsB7hb5Jvo45Sy27vmQ\na46D\r\n=JcJq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCuwK49nWLKHchDSOYY/xrXV9qG22CMXAduOPVgoJH5FAIhALKIrGNZ4QujAwulGim1IsJzZc/NQDbz5ps6+7DkTGmD"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.4.1-unstable_1552312987795_0.5164286728211043"},"_hasShrinkwrap":false},"2.4.1-unstable.0":{"name":"react-modelx","version":"2.4.1-unstable.0","description":"The State management library for React","main":"./dist/react-model.js","module":"./dist/react-model.esm.js","umd:main":"./dist/react-model.umd.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@commitlint/cli":"^7.5.2","@commitlint/config-conventional":"^7.5.0","@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","commitizen":"^3.0.7","cz-conventional-changelog":"^2.1.0","dotenv":"^6.2.0","husky":"^1.3.1","jest":"^24.1.0","prettier":"^1.16.4","react":"^16.8.4","react-dom":"^16.8.4","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"husky":{"hooks":{"commit-msg":"commitlint -E HUSKY_GIT_PARAMS"}},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![minified size](https://badgen.net/bundlephobia/min/react)](https://bundlephobia.com/result?p=react-model) [![Build Status](https://travis-ci.org/byte-fe/react-model.svg?branch=master)](https://travis-ci.org/byte-fe/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![downloads](https://img.shields.io/npm/dt/react-model.svg)](https://www.npmjs.com/package/react-model) [![Coverage Status](https://codecov.io/gh/byte-fe/react-model/branch/master/graph/badge.svg)](https://codecov.io/gh/byte-fe/react-model) [![Greenkeeper badge](https://badges.greenkeeper.io/byte-fe/react-model.svg)](https://greenkeeper.io/) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Both Class and Hooks Api\n\n⚔ Fully TypeScript Support\n\n📦 built with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n☂️ 100% test coverage, safe on production\n\n---\n\n## Quick Start\n\n[CodeSandbox: TodoMVC](https://codesandbox.io/s/moyxon99jx)\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Table of Contents\n\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n  - [getActions](#getactions)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component](#other-concept-required-by-class-component)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState, getActions } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React ^16.8.0 can use Hooks to connect the global store.\nThe actions return from useStore can invoke the dom changes.\n\nThe execution of actions returned by useStore will invoke the rerender of current component first.\n\nIt's the only difference between the actions returned by useStore and getActions now.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\noptional solution on huge dataset (example: TodoList(10000+ Todos)):\n\n1. use useStore on the subComponents which need it.\n2. [use useStore with depActions and React.memo to prevent child components rerender frequently.](https://github.com/ArrayZoneYour/react-model-todomvc/blob/master/src/components/TodoItem.tsx)\n\n[Demo Repo](https://github.com/ArrayZoneYour/react-model-todomvc)\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\n\nTo solve it, we provide a way to get the current state of model: getState\n\nNote: the getState method cannot invoke the dom changes automatically by itself.\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getActions\n\nYou can call other models' actions with getActions api\n\ngetActions can be used in both class components and functional components.\n\n```js\nimport { getActions } from './index.model'\n\nconst sharedActions = getActions('Shared')\nconst counterActions = getActions('Counter')\n\nconst model = {\n  state: {},\n  actions: {\n    crossModelCall: () => {\n      sharedActions.changeTheme('dark')\n      counterActions.increment(9)\n    }\n  }\n}\n\nexport default model\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nUsing function as return value can make your code cleaner when you modify the deep nested value.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"c2d6cf738316899122aa23dd5db0a85dd5db531e","_id":"react-modelx@2.4.1-unstable.0","_nodeVersion":"11.11.0","_npmVersion":"6.7.0","dist":{"integrity":"sha512-OBFgSsASt/7lRVJmpol88aCJGCgjY15XRz/1uL1MGaBPbJXB7tRB8scFY9eGRybLI7EuajwBVLqKYAdJOermUA==","shasum":"213f3d113d634720e75255147a3b99d7942aaacd","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.4.1-unstable.0.tgz","fileCount":14,"unpackedSize":54191,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJchm/DCRA9TVsSAnZWagAAhbsP/j40TpS7iiQ8XFqWX+6V\nqeyIt5m8prEec5KeEvDbVPxqgLHDVWuFhajWbtQHl1JSkTlI4nOQ7iQwewCW\nDMlTgpMA0qvWotx8xNHt3wHa8x5n71aUaFunhjb1MaqhgNRITUhTJp5sLP9r\n8+ezQR11rZ9H3UhPzP3u4b0102bB9ZYNdMN8kFbkYM4VNlQdyr/6ISOhVJwX\nzV1bf91EZ0UqA7QLdlXr+IocuYSRGS1QknK8QacH4YWWID9gn4RN0voYaDH8\n9qVcaxx9rUv25BEiU+hA3uZts9/CXY9/+xfLq2wprrbGqC8i0yjxOaytOaNk\nVggpR1pgbw3hWsU1qv8VaIwvUwGWm50YSxBdHG6ZFxKaIgIYx5CcBNTmOyh4\nfumeGIFvhZzxU0pfYHVr9Ofq+/n9vIx2rRaInvjKZw9kKYpkBsRX9kOAI5Ho\ngQQH+pIcuDGMM4GTBr0e2PpEROwOxeaUDNgaEomruL4h1/zf+WRThlrYkmHa\n2E2K7X19wW4NVMvFg3MWhWU1TWSO5xee37bbtursFIzc3XHt1ZNXWFud2rXG\nGJTjkzbK/bTKdmpwAD7vGiHvZnNq7/7FA+/l+zP6Zes5Utcbclf+bwkMq/hF\nXGoJn85hMpJdQmOcsuEPu1mga14/+1djrseg2JSKuHmQwteoUjiyxlgF3FLR\nuLjb\r\n=lNo6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF9/kgnZM1K5ctAX5iQffac/WIQsXKtddyxTMEHaUP1bAiEAmBak0Z9MeMpcC1O4h+BI3lS3CBmUxvsenDrFDIpvAkI="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.4.1-unstable.0_1552314306824_0.508051749319407"},"_hasShrinkwrap":false},"2.4.1-unstable.1":{"name":"react-modelx","version":"2.4.1-unstable.1","description":"The State management library for React","main":"./dist/react-model.js","module":"./dist/react-model.esm.js","umd:main":"./dist/react-model.umd.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@commitlint/cli":"^7.5.2","@commitlint/config-conventional":"^7.5.0","@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","commitizen":"^3.0.7","cz-conventional-changelog":"^2.1.0","dotenv":"^6.2.0","husky":"^1.3.1","jest":"^24.1.0","prettier":"^1.16.4","react":"^16.8.4","react-dom":"^16.8.4","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"husky":{"hooks":{"commit-msg":"commitlint -E HUSKY_GIT_PARAMS"}},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![minified size](https://badgen.net/bundlephobia/min/react)](https://bundlephobia.com/result?p=react-model) [![Build Status](https://travis-ci.org/byte-fe/react-model.svg?branch=master)](https://travis-ci.org/byte-fe/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![downloads](https://img.shields.io/npm/dt/react-model.svg)](https://www.npmjs.com/package/react-model) [![Coverage Status](https://codecov.io/gh/byte-fe/react-model/branch/master/graph/badge.svg)](https://codecov.io/gh/byte-fe/react-model) [![Greenkeeper badge](https://badges.greenkeeper.io/byte-fe/react-model.svg)](https://greenkeeper.io/) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Both Class and Hooks Api\n\n⚔ Fully TypeScript Support\n\n📦 built with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n☂️ 100% test coverage, safe on production\n\n---\n\n## Quick Start\n\n[CodeSandbox: TodoMVC](https://codesandbox.io/s/moyxon99jx)\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Table of Contents\n\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n  - [getActions](#getactions)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component](#other-concept-required-by-class-component)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState, getActions } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React ^16.8.0 can use Hooks to connect the global store.\nThe actions return from useStore can invoke the dom changes.\n\nThe execution of actions returned by useStore will invoke the rerender of current component first.\n\nIt's the only difference between the actions returned by useStore and getActions now.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\noptional solution on huge dataset (example: TodoList(10000+ Todos)):\n\n1. use useStore on the subComponents which need it.\n2. [use useStore with depActions and React.memo to prevent child components rerender frequently.](https://github.com/ArrayZoneYour/react-model-todomvc/blob/master/src/components/TodoItem.tsx)\n\n[Demo Repo](https://github.com/ArrayZoneYour/react-model-todomvc)\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\n\nTo solve it, we provide a way to get the current state of model: getState\n\nNote: the getState method cannot invoke the dom changes automatically by itself.\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getActions\n\nYou can call other models' actions with getActions api\n\ngetActions can be used in both class components and functional components.\n\n```js\nimport { getActions } from './index.model'\n\nconst sharedActions = getActions('Shared')\nconst counterActions = getActions('Counter')\n\nconst model = {\n  state: {},\n  actions: {\n    crossModelCall: () => {\n      sharedActions.changeTheme('dark')\n      counterActions.increment(9)\n    }\n  }\n}\n\nexport default model\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nUsing function as return value can make your code cleaner when you modify the deep nested value.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"c2d6cf738316899122aa23dd5db0a85dd5db531e","_id":"react-modelx@2.4.1-unstable.1","_nodeVersion":"11.11.0","_npmVersion":"6.7.0","dist":{"integrity":"sha512-IRTZ5LRDE4BI0ffEYu+n5F2c3EPM/wxIPfFO4lb6Oa41oL9UDb2Mt1kacgGoBu4JaAxfsD8dNNuahGlZT0ienQ==","shasum":"70c0cc061ce5c659ee3ce8df6550655376d34068","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.4.1-unstable.1.tgz","fileCount":14,"unpackedSize":54191,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJchnDoCRA9TVsSAnZWagAAwnoP/iogAkK5tSx4DVzIcdSH\nZlcxxemYv+lTZT9dLx5bRUg3W7dmqJ39dWwkuAkGc26WCS9F2/VTLGJJ7CmR\nUmhvLawNqnxWeRHzw3rxJykQGgkg5//24PojO1gAvcx/5s3PQIEzn2j8Ztg6\nOIv/U5UoJDYiwO96oXN3wIPxucQGnUW6DtnI//S9qPHx04zZQsV6FsxFwLHD\n4bwHKcmgPYePMPbnOz/uyiQwyw6zG7+Acp+3ucooVm+DR4WpXefm1bLDxJQ4\nP8a+GW4PQkUaZ3uO7oHKCTTof5jPw17KFfMemj3ARP1zYKCtkMWXDsV7sG/H\nydc0StLynKzHbHeS3ihd0PkNopEZOw0Wu/CwE6bG04t24y2ToXHbur1VTZFe\ngbEU38TFkgC1hB+LkWljoKJRkWXp4kuFINdZYTr20YO0ySi/KgE1dgbh+dWk\nAP81zfFb3U4ID3096NE1Z5Fa8A/3dg7npiBs048/GL96CT5MbWJHBHZJD0Zw\nb59k+fUzwNU4YlzteuOdM0JbUxFI9Us+BeT/bjQT0yFkZcyWmxawnaCbNKUb\nukNGq6i718b/63zQ4/B5dftpK7r6Fh6jq58Q1lvnDuY7OPxB23wFEFsSwnoA\nHmD61vP0pHx58gGSuQ9upqWLzqcW8URThOjMbAi7yuseSn5oq81TwWUKQGKv\nO8To\r\n=k4qY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC1uwjn6I+yU7UtVVHBrRq9QuBhN0o3XqA/7WaZjh/taAIgBKZrT1BzoeDjbBRBA8lzt+xbA9mA4momh8N7V0k75SI="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.4.1-unstable.1_1552314599939_0.3477791945893194"},"_hasShrinkwrap":false},"2.4.1-unstable.2":{"name":"react-modelx","version":"2.4.1-unstable.2","description":"The State management library for React","main":"./dist/react-model.js","module":"./dist/react-model.esm.js","umd:main":"./dist/react-model.umd.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@commitlint/cli":"^7.5.2","@commitlint/config-conventional":"^7.5.0","@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","commitizen":"^3.0.7","cz-conventional-changelog":"^2.1.0","dotenv":"^6.2.0","husky":"^1.3.1","jest":"^24.1.0","prettier":"^1.16.4","react":"^16.8.4","react-dom":"^16.8.4","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"husky":{"hooks":{"commit-msg":"commitlint -E HUSKY_GIT_PARAMS"}},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![minified size](https://badgen.net/bundlephobia/min/react)](https://bundlephobia.com/result?p=react-model) [![Build Status](https://travis-ci.org/byte-fe/react-model.svg?branch=master)](https://travis-ci.org/byte-fe/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![downloads](https://img.shields.io/npm/dt/react-model.svg)](https://www.npmjs.com/package/react-model) [![Coverage Status](https://codecov.io/gh/byte-fe/react-model/branch/master/graph/badge.svg)](https://codecov.io/gh/byte-fe/react-model) [![Greenkeeper badge](https://badges.greenkeeper.io/byte-fe/react-model.svg)](https://greenkeeper.io/) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Both Class and Hooks Api\n\n⚔ Fully TypeScript Support\n\n📦 built with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n☂️ 100% test coverage, safe on production\n\n---\n\n## Quick Start\n\n[CodeSandbox: TodoMVC](https://codesandbox.io/s/moyxon99jx)\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Table of Contents\n\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n  - [getActions](#getactions)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component](#other-concept-required-by-class-component)\n  - [Provider](#provider)\n  - [connect](#connect)\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState, getActions } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React ^16.8.0 can use Hooks to connect the global store.\nThe actions return from useStore can invoke the dom changes.\n\nThe execution of actions returned by useStore will invoke the rerender of current component first.\n\nIt's the only difference between the actions returned by useStore and getActions now.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\noptional solution on huge dataset (example: TodoList(10000+ Todos)):\n\n1. use useStore on the subComponents which need it.\n2. [use useStore with depActions and React.memo to prevent child components rerender frequently.](https://github.com/ArrayZoneYour/react-model-todomvc/blob/master/src/components/TodoItem.tsx)\n\n[Demo Repo](https://github.com/ArrayZoneYour/react-model-todomvc)\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\n\nTo solve it, we provide a way to get the current state of model: getState\n\nNote: the getState method cannot invoke the dom changes automatically by itself.\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getActions\n\nYou can call other models' actions with getActions api\n\ngetActions can be used in both class components and functional components.\n\n```js\nimport { getActions } from './index.model'\n\nconst sharedActions = getActions('Shared')\nconst counterActions = getActions('Counter')\n\nconst model = {\n  state: {},\n  actions: {\n    crossModelCall: () => {\n      sharedActions.changeTheme('dark')\n      counterActions.increment(9)\n    }\n  }\n}\n\nexport default model\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nUsing function as return value can make your code cleaner when you modify the deep nested value.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n","readmeFilename":"README.md","gitHead":"c2d6cf738316899122aa23dd5db0a85dd5db531e","_id":"react-modelx@2.4.1-unstable.2","_nodeVersion":"11.11.0","_npmVersion":"6.7.0","dist":{"integrity":"sha512-AF+0E+/7quALuQ2k47hUXx0X4H3ddBIlxORdwfRgwXFG1mO2oBF0+o/NnroLvYo9189hSSKnkjeH6MF8a/6h3w==","shasum":"567f59aa8091e414ddcde0904fd96b370a1e6d06","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.4.1-unstable.2.tgz","fileCount":14,"unpackedSize":54244,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJchnIeCRA9TVsSAnZWagAAfF4P/3cXbKuCUY0+LKj1NArD\nEdw7XIXB1M6m8+WtxViPc8kZaZfjsANvS+uCGmJZBgq/NeVEc0/eV1QEl4zm\n8w8clz0rpu7CbHoBDZiKr3XKffdmNwzBkFYABp0eBbo8hQz4YB4CshnCrElb\nFRC6XfQaN8aP2O15EYhy06gU0GAug5ooEqb3tVBavmuqE4uya8DxbqyY2XqS\nvfMKV7w2CpI75hB+cGm5Xo8uYyFjPA14K3uZ2arnp2geh4J8IC1BG8NW72XV\nPGyp720oRaxzH+QV41aRnmAq+TDXJ2EiuHSLOqWam3IC1jsefk8ObLXS/pcI\nLZVdgHNbHBELonoRa6/F+29LZBz0yK0lyNC5VWttI29SNIqtSId4jTwm8HV1\n83N9FgxK/pMm1of5+90HY5cWd6B/N8QZrOCUIRZNH/r6LYDU76qp7ac6ES2F\nSCNgBvD8pSy8guok7oyJs4hEk67xEdFf/lLyMlQ5P40B2/EfM9Nf4SRgwLPU\nDFUPgI01FjqQ4tOt6rzgaKBSTGqb2gJhzavO6wPqBZzqPRdY/KZhQlZUeUri\npzIG96rqOcMipWfwGWf9XcooHFelhFPRh5OsGNZ6QvKb8gNp42EM6NAGw6nH\n62aHVS0SSeKQ+w3XfMpI9cAXxyL3S5gQdYgccCDAMGhvHD700peW7Yl6QpCz\n8pI9\r\n=tPME\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDPWwA9Im0m9ec8+3qERwLtQojQfE09CreKMotZh0IQDwIgVDgW9qHSPeYsr/9ydRQCKC+datgJRlb0nCSiW11w+A8="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.4.1-unstable.2_1552314909489_0.34115108099346547"},"_hasShrinkwrap":false},"2.4.1":{"name":"react-modelx","version":"2.4.1","description":"The State management library for React","main":"./dist/react-model.js","module":"./dist/react-model.esm.js","umd:main":"./dist/react-model.umd.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@commitlint/cli":"^7.5.2","@commitlint/config-conventional":"^7.5.0","@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","commitizen":"^3.0.7","cz-conventional-changelog":"^2.1.0","dotenv":"^6.2.0","husky":"^1.3.1","jest":"^24.1.0","prettier":"^1.16.4","react":"^16.8.4","react-dom":"^16.8.4","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"husky":{"hooks":{"commit-msg":"commitlint -E HUSKY_GIT_PARAMS"}},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"gitHead":"1d93fecdf93032a012acc41c8f58221ec6a18dd1","_id":"react-modelx@2.4.1","_nodeVersion":"11.10.1","_npmVersion":"6.7.0","dist":{"integrity":"sha512-o/hVCkooearb5WeMmFAULldqFgGJpjQcpFteX33YdHH4UOH3ZaAOOCJ7f+G79dfqJ91HeC2zLW9hkCkIHQidMA==","shasum":"1a7d4879418bafa71b17c8cb4a6ebb64b854ee53","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.4.1.tgz","fileCount":14,"unpackedSize":54402,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJch1WHCRA9TVsSAnZWagAAl/MQAJh0YThQcIg/dZahGUv5\npV2eP+2rpF4DAAMKkVVW89CI+9sPRG5x1uWGzcp6FUSQUKYJ8C5m+bAPVjzQ\nD3M304Kcu9esSSASu6coYA3wNOXBGhq9HkKkIf054g/Us97E84rGZLiRT23Z\n4w0OMReH0O6W6E7EtebrrIoHZyD+zqhHXoOvmdOXgS0P+2+ENSoGj2PbY7Pv\nBMukq/g59GGR0bfV8pP7uiQ/yfE1CNkcrTDo6qHDKmS29oR40DOn8W3zD4BF\nkKOt5/dWAjrTOAXbJD6V40OV4Nw8v5rJLQSjnHmfsDfmTfZrHnU9qqB24dWx\nvKrZ4iLfnDnfaTaMjRrpXE+/uBmgNEz8P9JO+Gis2K4rPYUE6AVU2xOtyLVw\nLoPsML4vJ0xJ/JvkbdqgSPGA0uHR82sevi6tkIpoF/kVbxA4wCPmEOJuQec9\nj/ueYUwJ7FNZgQGjXdx6CK+MLe0hWcTGguEEufUC8eiXWKY/tnWKlFSoAzZt\nsQV6Q+Psg8v2FiiuLviXAHkjs3vjjwULl9Wm0jc61qoidGsikkb0mCHqpPjs\ncqvJx8x8WwjHNcYwQG5rwHRm5Dby764uBnoHEXSnNmPB+/nS+bCsAOmR/5D7\nE1GmA3KXWMAXLQ++G2h6v0/KbT991yR/PK36QGnXS6dTZVYjUl+uy6zEqt/i\nHU8c\r\n=tG2f\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBPFjyeJ4RYBgIOqzrzN/uAlX+xdpNDb/YLpf4ycKtneAiEAzQ3xZ2WeNgz24LIhZg4Gm6BD+b8qNdFgtPALSLKuvlY="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.4.1_1552373126365_0.17032293099497253"},"_hasShrinkwrap":false},"2.4.2":{"name":"react-modelx","version":"2.4.2","description":"The State management library for React","main":"./dist/react-model.js","module":"./dist/react-model.esm.js","umd:main":"./dist/react-model.umd.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@commitlint/cli":"^7.5.2","@commitlint/config-conventional":"^7.5.0","@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","commitizen":"^3.0.7","cz-conventional-changelog":"^2.1.0","dotenv":"^6.2.0","husky":"^1.3.1","jest":"^24.1.0","prettier":"^1.16.4","react":"^16.8.4","react-dom":"^16.8.4","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"husky":{"hooks":{"commit-msg":"commitlint -E HUSKY_GIT_PARAMS"}},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"gitHead":"8a44981a7ce749a4021b672807fd3aea2a95124d","_id":"react-modelx@2.4.2","_nodeVersion":"11.11.0","_npmVersion":"6.7.0","dist":{"integrity":"sha512-pYoh6aQy/pbXoNQSt4pOsN0MjWTmIHjbiRnVqCs1P+pAVfbJ7cIDkHW5Jd92jTu7oRU4AEvkAkPzR6KjYrZtVA==","shasum":"29c47361ce55811f0b7ff7a4bc549623d257da37","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.4.2.tgz","fileCount":14,"unpackedSize":55368,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJch2vUCRA9TVsSAnZWagAAhYIP/0GanOvJ4RY+/iiOS5N+\nQysO3VTsVMFZNZDIHJdVm12p8ldOrMCzySWzjoCJTtEPQEl/WP4GcNQkBx/1\nYnX5Owe02omiYOtubkSMcjCQhsgsWS2K3EFLx4c37IUIlkMU6ADQKWrFbuvp\ndyNriVmNRtAkhFnVeHHmxx7/ccTH9KbUDmWtBnbteCAA3g6lUouGUFa+0JtQ\nVrmm6jXzA2iNsbKq136tj8Fjaczatpi7WZn5P+Vdb4he143ykzjK4mqeVqgt\njqK5SxH4jzyeqV8yksgV9K/awfKTi1hxYU+i9Pwz0pgxOeeYrLMJ29Skwa9q\nMnM/rZB9npww3qeAL+f6X0zse3ynOuotlqGl9UAcLkNHpokUD+bdQIs5CZbm\nm4V6TkUwLwuH/WL/NgzxuIuKoc6bqrGPf3akdX/oS9Z9XRKfU4rXWddBsBHQ\nGAn6mU/jSHFz8QpnwKLk7SNGo2nHB211HXmqnQ+G2CBbglkO8kl1m4RJ//25\nPrSNoxc0ckNRmjTSQMqYdpc6n3E/RxOfpqCOFvG8hO6+wdraQ3ISW+to/lDr\njirZV9hnFmwI6ImlTaTsB6R6ALGvkLFICTJcPJa0c2JJx5e0q9a7svyTNZL9\nMC9ajhNMgkMrm+BYJZGX5dTNlPKJtqpMFwOPOBZ4Fwi1ixh6GPDCA716+vsL\nqTsz\r\n=lz0e\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCtljPHU62wqhXzX4MPPO2qGwYMF980AlxOvoyB3ro2hwIgftOb66glFNfotJN9CJDUEAMMxQcWeDK/dg+eBUwOJzA="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.4.2_1552378835439_0.9725529569825586"},"_hasShrinkwrap":false},"2.5.0":{"name":"react-modelx","version":"2.5.0","description":"The State management library for React","main":"./dist/react-model.js","module":"./dist/react-model.esm.js","umd:main":"./dist/react-model.umd.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@commitlint/cli":"^7.5.2","@commitlint/config-conventional":"^7.5.0","@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","commitizen":"^3.0.7","cz-conventional-changelog":"^2.1.0","dotenv":"^6.2.0","husky":"^1.3.1","jest":"^24.1.0","prettier":"^1.16.4","react":"^16.8.4","react-dom":"^16.8.4","react-testing-library":"^5.8.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"husky":{"hooks":{"commit-msg":"commitlint -E HUSKY_GIT_PARAMS"}},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"gitHead":"884366568d9bed69f753d7934d879bf5ab2eb43b","_id":"react-modelx@2.5.0","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-5snremgC2Utr6q+x6gPSSGewc/ydpLdkLpIT9n+YizgoYV0+XYc6YvVPIbr15ernsr1PM73usZbBfdYPw9WprA==","shasum":"6dfb333d019b0ffa8e04d52fb857dacbc3323854","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.5.0.tgz","fileCount":14,"unpackedSize":56966,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJch7VOCRA9TVsSAnZWagAAP+UQAIlyiePQXprqnDhANNZW\nvKztmEQ0kW7a08JFvwL+NyzdYhOddCbumaBzPsMlBBd/ZHyrBM7OefpKlH5d\nOnyIQwFAC3YY2WdJ7PuaR8AGRUow7plb7aKhP6a+ayvltS1FmA54Os7a7blr\nMPG1Xpbg9QzxPYZD+YPZ4Rm+ztkJcNKNzAgLVqRmiUjMhnAdusIVA06dXf1x\nfpGQdVfFyRtNwBO/wEOQPlDiI0gYDdQt3LQLELRtSqWHWlT3Xb51i8AeSiyV\n8UH0qmW6u7ISJPppqoKiG2SuyYZiWwqcwHGkLS35HG2JN3lwNM8SeVY5xnHl\nse4JBFBWYzKpvRrHvtEZvtsE4MHvV9GSBNCtiR9xgw56OLIHExQSyPhuGM0e\n+5KyWR46vYjXA2tdTgnWPpB8afPQ6oRSXLK7v/iZw0CYGfADB88+TSIJTAS0\nhzQRmKVwUj4KfyVBXak6kM8Ugep1uuyLt5GaFXvgZr8CiMbryUuRujUK6FXS\nMDuG44UryIkwBn90Wvyv9A3EeeklLiGLsjoM0iNQ4f/rsi67FFPRgiO+H3yZ\ncoSfDXUkprdiMU9KpsUEoXB2PAJrD3VpTJSxbvUGUvDSjhBf2qGr8+82K8kJ\nlesNvJ+Rl/ss3FpoCeHpFSR9k9Z8jSMXAJLWn9wJyQfWu8zzxMSLoToCLmIf\nuBj2\r\n=vfUm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCQ71IrNKwn9odrNyJhSl8V2znoF+Uv2gMTiYN0c0XA+wIgQGv5e5+Lv7W52NbdjOMemcGK6vtPaINlq5BMRXlgHGU="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.5.0_1552397645939_0.3446912974891889"},"_hasShrinkwrap":false},"2.5.1":{"name":"react-modelx","version":"2.5.1","description":"The State management library for React","main":"./dist/react-model.js","module":"./dist/react-model.js","umd:main":"./dist/react-model.umd.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@commitlint/cli":"^7.5.2","@commitlint/config-conventional":"^7.5.0","@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","commitizen":"^3.0.7","cz-conventional-changelog":"^2.1.0","husky":"^1.3.1","jest":"^24.1.0","prettier":"^1.16.4","react":"^16.8.4","react-dom":"^16.8.4","react-hooks-testing-library":"^0.3.6","react-testing-library":"^6.0.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"husky":{"hooks":{"commit-msg":"commitlint -E HUSKY_GIT_PARAMS"}},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"gitHead":"912d5ffd9c360c42c94bb032b093e26ed4199df2","_id":"react-modelx@2.5.1","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-F28kSUzYEE1VRy04bcE66okWFp/eAmzu6OlLNlYJmCnyhXuvHN19ZmJMLaIIfmkrYpUCS1ug26p74vNvJ/KA1Q==","shasum":"1a47eea52d4b694e49e8a0517bc4607bdd2ecb7b","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.5.1.tgz","fileCount":15,"unpackedSize":57812,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJci4IpCRA9TVsSAnZWagAA7BAP/R5fySgt7CoN9ZE2a0tf\nAZL2BElEOlMtql296TQRZOpT5kR3RhBuxSHMylpiIWCrG89RlMck2pUjU51E\nMlakT0ixA54Pqsg4HW4U/PNvDH67yvMQHHVW+S2dLB/vFHC7pga6Fhlk2FpN\ndI7nmJvJlBgS0PsfxC+5WR7wZnHgxnQtLwdusMJg44hDVNoXiWT4O48GWhro\nWvL47WDG3195a5FNy7X/Xwj5nVhlDaNuZoYaSQBNsB79PelCcDkk0DWJuNwg\ntwhyYurGVB0QX48jQJGdqngJ2bwedOqweFq0grw8h1V5YtVbwLugmJNBHwYk\nwCIjuGL2rJ+0okW+4ZElcO0MwKpqYn9bla5rK0wEzEFxSD4psW8EFWKArqZv\n7CGeApzhBN4O3N4OxZLkTqOcZqB+MC+5cb+7sFF9+RL5Bh8k4/1U6BAYAYxp\n6bu2XbRtrPH4bG2qjwsGiOS1iseZ0Fs44hbWnX33LAN9b1tcl2z3S6dy9bs1\ny6XwMx+0x1TQUFD+Bo8bNmCnri3cO2Vy836+EN7Let8PuZxQwZvYD/Kj1daa\nNVQ8+TPLgw6SvmFZVGf1kb4npBTL2t+0vig+UowgSX9XCUldX7BrM7dwSac8\nzApVsTUE4CjpSKY7yoiuOGL8B8bm14a8pWxqKGHQmnBUPWo7YWlzIjKf6w4Z\nbTtE\r\n=HdKQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH/opJPhWThe3tTMZxDWnjhK0RYpl6AJV1h20hipQSyvAiEAv9wA7GYV2AXpCcEM6zAPgmD1Ov2tESqqy1XVul2lhps="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.5.1_1552646696552_0.023680524815303583"},"_hasShrinkwrap":false},"2.5.2":{"name":"react-modelx","version":"2.5.2","description":"The State management library for React","main":"./dist/react-model.js","umd:main":"./dist/react-model.umd.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@commitlint/cli":"^7.5.2","@commitlint/config-conventional":"^7.5.0","@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","commitizen":"^3.0.7","cz-conventional-changelog":"^2.1.0","husky":"^1.3.1","jest":"^24.1.0","prettier":"^1.16.4","react":"^16.8.4","react-dom":"^16.8.4","react-hooks-testing-library":"^0.3.6","react-testing-library":"^6.0.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"husky":{"hooks":{"commit-msg":"commitlint -E HUSKY_GIT_PARAMS"}},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"gitHead":"912d5ffd9c360c42c94bb032b093e26ed4199df2","_id":"react-modelx@2.5.2","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-R0vop/Ec45sRSECwmCRG0IGPOCyEqA/nOz8QiRfE/xGB6+dpgfUWEYTCKqimhOHe4omMyR9YgirGbK7bxsn8dw==","shasum":"8f24b8b7048b7382a5d5c9841aab9b909494bb31","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.5.2.tgz","fileCount":16,"unpackedSize":65822,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJci4VuCRA9TVsSAnZWagAAfE8QAJO/1P166gJZCLNi1dU6\nOmDW6QhG94UtcQ7FpfFoUwGEDO7Mia58rtq+AlYLSIl505W1nr/EbwEJW09P\n3z+XYysGAlVVCW8yuE2K1oWBj611VAGk8eO/EIko2rYHxPfkVMYvahk6nPyL\njbvyACb2I1mbiNHyfniwetDbCjcI5Kc95/w9ZhKgU9740LLR0apzXTPx3koq\nZBMUBY/6a4IMmT9ubvVpw9EZ0FeJZCqrsKBQlqxoIBQtlxoBh4HLeJxy97Df\nxh2qXMglgqdQ+02AwUCbad4RdVQQA/qmjsF8EZOkm2IzWeMuNDjNsk8AklwE\nssB06rrNik9HgjhIwFBeGmac0WOmnILownzan2llcustK+0EGWnPOQlfm9yl\n/zr+Rbsz2hlc0iK+ojvll7p5Q7vvlrhFCDtDOtKJlRrQNlheBjqkKpH+r0hs\nDNSyxfldlAWFeTME+7VquImaDngLe21stsEq34/Qeyc8rOXua/H+xkst0MCv\nwHUgKuxkNI5KBCsUV4WZggdAjFWO42AeQ2xq0G97j1hi8cUUQ1xYiy25RJ/H\n87nj1I/7Jc98o8ingK1Q/Y2dZa3jP6Bm7iD/HjoQjse5ufD0tgtHBUeE/j0q\nw9thS6Zyin136+fuSHV6RG0iT2yKf150vJjxUPY4aGx0o4jJ7TSB6vxRDQ37\ndoiZ\r\n=d42E\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCgIYYsBW0WBIvbT4V1qQMR8046LK6QN4GPxSnijA6cbgIhAN8CGMXNXen1fr/DqJU87oUOFA3MG1qbcVrlx4JSKVcs"}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.5.2_1552647533095_0.6525040255872827"},"_hasShrinkwrap":false},"2.5.3":{"name":"react-modelx","version":"2.5.3","description":"The State management library for React","main":"./dist/react-model.js","umd:main":"./dist/react-model.umd.js","types":"./src/index","scripts":{"build":"microbundle -o ./dist --sourcemap false","commit":"git-cz","test":"jest --silent","test:coverage":"jest --collect-coverage --silent"},"keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","dependencies":{"immer":"^2.0.0"},"peerDependencies":{"react":"^16.3.0","react-dom":"^16.3.0"},"devDependencies":{"@commitlint/cli":"^7.5.2","@commitlint/config-conventional":"^7.5.0","@types/jest":"^24.0.5","@types/node":"^11.9.4","@types/react":"^16.8.2","@types/react-dom":"^16.8.0","commitizen":"^3.0.7","cz-conventional-changelog":"^2.1.0","husky":"^1.3.1","jest":"^24.1.0","prettier":"^1.16.4","react":"^16.8.4","react-dom":"^16.8.4","react-hooks-testing-library":"^0.3.6","react-testing-library":"^6.0.0","ts-jest":"^24.0.0","typescript":"^3.3.1"},"husky":{"hooks":{"commit-msg":"commitlint -E HUSKY_GIT_PARAMS"}},"repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"},"homepage":"https://github.com/byte-fe/react-model#readme","config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"gitHead":"912d5ffd9c360c42c94bb032b093e26ed4199df2","_id":"react-modelx@2.5.3","_npmVersion":"6.4.1","_nodeVersion":"10.15.0","_npmUser":{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"},"dist":{"integrity":"sha512-2LMX5RU3viYFacWg3hCya/sY/UuIKAl7IimBUi+1vqyzXEORIE7T50rX1wEl9nKUYSj9UPdicCLGbk1KOZg0/A==","shasum":"020c408820900a49e3ff9a4e199c3b4c525ac60c","tarball":"https://registry.npmjs.org/react-modelx/-/react-modelx-2.5.3.tgz","fileCount":15,"unpackedSize":58228,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJci4XMCRA9TVsSAnZWagAA7YgP/3zFRbF11GWtk9ytbJjD\nrly+GRHwbyHENvGiaXXLvNKQF3ndsmCS6fjFIcIzWCdOFPInFlK6NDR4oA2f\n+91Cs05tI86VE0nkBaMlrdLab/Sqc+tLnlOiFlvJAr0x1UKwlTXx8XHKm4ih\nK/eMS/yJQyaUFOiV7FyXG2KfinD3+6Sur7JYsPyz+Ua6zKou4uDn4+Aa4uVd\n2Rm3NVJElm7DbpWgmQtA0QN2lYn/G7D+LBc14o3jlOJC6Qq4T6JtSsoXUnCZ\nQpQsy3Bzq7gALh3fEHR6fEQpKvyhs0OMdpSordmmlNVnw+8+QX3efpb4U888\nSSQcSUIoD8EDb+Oeh9+TlSpGxFlQlbHq/ssVh+njPeq6NA0yF7ecidlaEvqq\n9cmnhfoMbLVFKIwmhGcZwougfWgBuJikM6YFTxfBx25JPgGJ+gNB2ihNZrTx\nboISG2pu1/APOUcDOD3vU6Toc0tI10CdZjmiDgLrjvxZaBtkO1oRRgjbVaVh\nW2Gs+Vg76uHdZ5ovIjH6l+qTpuw8hM3DeDpGK/1Ls2+9uJN5f7ZIKPtwb2uh\nTOKyD1O5LXurq9n1S7+XGG3f0KLP8ZGLPSm0mXDWzox8O8dkeb34iMgtCVJg\n5hJ9p6+Fthe9xzj/Oy2RGEYwVy/qrZVu/V9As7xRNR11Xldep5F5qa3f2Ms7\nksW6\r\n=MjxJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDyXLNYQA8RSRXT7VF59ZwMxyRzeD/vwxAuVklMIeqgzgIgYRV1+PssJjv/yqlffEhdzr70q3GOohDACBN9UyekG0E="}]},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-modelx_2.5.3_1552647627320_0.2994038089425881"},"_hasShrinkwrap":false}},"time":{"created":"2018-12-06T08:13:54.422Z","1.0.0-alpha":"2018-12-06T08:13:54.547Z","modified":"2022-05-14T14:53:25.095Z","1.0.0-alpha.0":"2018-12-06T08:34:00.737Z","1.0.0-alpha.1":"2018-12-06T08:42:01.899Z","1.0.0-alpha.2":"2018-12-06T09:19:19.719Z","1.0.0-alpha.3":"2018-12-09T03:20:02.990Z","1.0.0-alpha.4":"2018-12-21T04:28:55.530Z","1.0.0-alpha.5":"2018-12-21T06:05:12.533Z","1.0.0-alpha.6":"2018-12-21T06:05:30.886Z","1.0.0-alpha.7":"2018-12-21T08:27:37.572Z","1.0.1":"2018-12-26T08:05:30.732Z","1.0.2":"2018-12-26T08:38:37.599Z","1.0.3":"2018-12-26T08:50:24.545Z","1.0.4":"2018-12-27T10:04:17.240Z","1.0.5":"2018-12-28T15:56:45.025Z","1.0.6":"2018-12-28T16:11:58.744Z","1.0.7":"2018-12-29T10:42:50.750Z","1.1.0":"2018-12-31T14:24:45.922Z","1.1.1":"2019-01-03T09:39:33.710Z","1.1.2":"2019-01-03T10:13:25.696Z","1.1.3-unstable":"2019-01-04T06:54:46.928Z","1.1.3":"2019-01-04T07:10:03.153Z","1.1.4-unstable":"2019-01-10T03:02:02.323Z","1.1.4":"2019-01-10T03:05:43.247Z","1.1.5-unstable.0":"2019-01-10T07:49:46.098Z","1.2.0-alpha.0":"2019-01-11T03:35:03.378Z","1.2.0-alpha.1":"2019-01-11T04:15:19.506Z","1.2.0-alpha.2":"2019-01-11T04:21:59.176Z","2.0.0-alpha.0":"2019-01-14T03:20:17.667Z","2.0.0-alpha.1":"2019-01-14T03:43:28.667Z","2.0.0-alpha.2":"2019-01-14T06:39:54.647Z","2.0.0":"2019-01-14T06:45:36.488Z","2.0.1":"2019-01-14T06:47:03.258Z","2.0.2-unstable.0":"2019-01-15T05:02:03.105Z","2.0.2":"2019-01-15T08:18:35.359Z","2.0.3":"2019-01-15T08:28:30.977Z","2.0.4-unstable":"2019-01-15T08:35:03.640Z","2.0.4":"2019-01-15T08:36:27.940Z","2.0.5-unstable.0":"2019-01-16T08:01:18.059Z","2.0.5":"2019-01-16T08:19:22.720Z","2.0.6-unstable.0":"2019-01-17T15:31:46.733Z","2.0.6-unstable.1":"2019-01-17T15:46:49.514Z","2.0.6-unstable.2":"2019-01-17T16:59:53.307Z","2.0.6-unstable.3":"2019-01-17T17:04:04.557Z","2.0.6":"2019-01-17T17:17:33.104Z","2.0.7-unstable.0":"2019-01-18T03:31:45.300Z","2.0.7":"2019-01-18T03:42:06.787Z","2.0.8-unstable.0":"2019-01-18T03:47:13.742Z","2.0.8":"2019-01-18T03:54:52.499Z","2.0.9":"2019-01-20T13:59:46.532Z","2.0.10":"2019-01-20T14:10:42.035Z","2.0.11-unstable.0":"2019-01-20T15:44:52.472Z","2.0.12-unstable":"2019-01-21T05:33:28.696Z","2.0.12-unstable.0":"2019-01-21T05:43:02.518Z","2.0.12":"2019-01-21T06:17:18.490Z","2.0.13-unstable.0":"2019-01-21T15:53:13.250Z","2.0.13-unstable.1":"2019-01-22T03:30:43.091Z","2.0.13":"2019-01-22T03:38:27.906Z","2.1.0-unstable.0":"2019-01-23T16:13:20.098Z","2.1.0-unstable.1":"2019-02-06T14:45:45.200Z","2.1.0":"2019-02-06T14:49:36.537Z","2.2.0-unstable":"2019-02-17T06:58:37.119Z","2.2.0":"2019-02-17T07:09:17.126Z","2.2.1":"2019-02-19T05:26:02.931Z","2.2.1-unstable":"2019-02-19T05:32:36.389Z","2.2.1-beta":"2019-02-19T05:36:34.671Z","2.2.2-unstable.0":"2019-02-22T08:14:08.037Z","2.2.2-unstable.1":"2019-02-22T08:57:36.298Z","2.2.2-unstable.2":"2019-02-22T09:02:36.924Z","2.2.2":"2019-02-22T11:03:38.134Z","2.3.0":"2019-02-25T09:04:38.816Z","2.3.0-unstable":"2019-02-25T09:04:56.724Z","2.3.1":"2019-02-26T05:37:39.857Z","2.3.2":"2019-03-01T06:50:03.991Z","2.4.0":"2019-03-07T11:22:33.647Z","2.4.1-unstable":"2019-03-11T14:03:07.911Z","2.4.1-unstable.0":"2019-03-11T14:25:06.970Z","2.4.1-unstable.1":"2019-03-11T14:30:00.081Z","2.4.1-unstable.2":"2019-03-11T14:35:09.801Z","2.4.1":"2019-03-12T06:45:26.550Z","2.4.2":"2019-03-12T08:20:35.576Z","2.5.0":"2019-03-12T13:34:06.079Z","2.5.1":"2019-03-15T10:44:56.762Z","2.5.2":"2019-03-15T10:58:53.286Z","2.5.3":"2019-03-15T11:00:27.543Z"},"maintainers":[{"name":"arrayzoneyour","email":"hustliyidong@gmail.com"}],"description":"The State management library for React","keywords":["react","model","state-management","react-hooks"],"author":{"name":"ArrayZoneYour","email":"hustliyidong@gmail.com"},"license":"MIT","readme":"# react-model &middot; ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://img.shields.io/npm/v/react-model.svg?style=flat)](https://www.npmjs.com/package/react-model) [![minified size](https://badgen.net/bundlephobia/min/react)](https://bundlephobia.com/result?p=react-model) [![Build Status](https://travis-ci.org/byte-fe/react-model.svg?branch=master)](https://travis-ci.org/byte-fe/react-model) [![size](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js?compression=gzip)](http://img.badgesize.io/https://cdn.jsdelivr.net/npm/react-model/dist/react-model.js) [![downloads](https://img.shields.io/npm/dt/react-model.svg)](https://www.npmjs.com/package/react-model) [![Coverage Status](https://codecov.io/gh/byte-fe/react-model/branch/master/graph/badge.svg)](https://codecov.io/gh/byte-fe/react-model) [![Greenkeeper badge](https://badges.greenkeeper.io/byte-fe/react-model.svg)](https://greenkeeper.io/) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)\n\nThe State management library for React\n\n🎉 Support Both Class and Hooks Api\n\n⚔ Fully TypeScript Support\n\n📦 built with microbundle\n\n⚙️ Middlewares Pipline ( redux-devtools support ... )\n\n☂️ 100% test coverage, safe on production\n\n🐛 Debug easily on test environment\n\n![Debug Easily](https://github.com/byte-fe/react-model-experiment/raw/0974f43bae2b3778ecc8fc65c1143ec1c50914c9/images/debug.jpg)\n\n---\n\n## Quick Start\n\n[CodeSandbox: TodoMVC](https://codesandbox.io/s/moyxon99jx)\n\n[Next.js + react-model work around](https://github.com/byte-fe/react-model-experiment)\n\ninstall package\n\n```\nnpm install react-model\n```\n\n## Table of Contents\n\n- [Core Concept](#core-concept)\n  - [Model Register](#model-register)\n  - [useStore](#usestore)\n  - [Model](#model)\n  - [getState](#getstate)\n  - [getActions](#getactions)\n- [Advance Concept](#advance-concept)\n  - [immutable Actions](#immutable-actions)\n  - [SSR with Next.js](#ssr-with-nextjs)\n  - [Middleware](#middleware)\n- [Other Concept required by Class Component](#other-concept-required-by-class-component)\n  - [Provider](#provider)\n  - [connect](#connect)\n- [FAQ](#faq)\n  - [How can I disable the console debugger?](#how-can-i-disable-the-console-debugger?)\n\n## Core Concept\n\n### Model Register\n\nreact-model keep the state and actions in a global store. So you need to register them before using.\n\n`model/index.model.ts`\n\n```typescript\nimport { Model } from 'react-model'\nimport Home from '../model/home.model'\nimport Shared from '../model/shared.model'\n\nconst models = { Home, Shared }\n\nexport const { getInitialState, useStore, getState, getActions } = Model(models)\nexport type Models = typeof models\n```\n\n[⇧ back to top](#table-of-contents)\n\n### useStore\n\nThe functional component in React ^16.8.0 can use Hooks to connect the global store.\nThe actions return from useStore can invoke the dom changes.\n\nThe execution of actions returned by useStore will invoke the rerender of current component first.\n\nIt's the only difference between the actions returned by useStore and getActions now.\n\n```tsx\nimport React from 'react'\nimport { useStore } from '../index.model'\n\n// CSR\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button onClick={e => actions.increment(33)}>home increment</button>\n      <button onClick={e => sharedActions.increment(20)}>\n        shared increment\n      </button>\n      <button onClick={e => actions.get()}>fake request</button>\n      <button onClick={e => actions.openLight()}>fake nested call</button>\n    </div>\n  )\n}\n```\n\noptional solution on huge dataset (example: TodoList(10000+ Todos)):\n\n1. use useStore on the subComponents which need it.\n2. [use useStore with depActions and React.memo to prevent child components rerender frequently.](https://github.com/ArrayZoneYour/react-model-todomvc/blob/master/src/components/TodoItem.tsx)\n\n[Demo Repo](https://github.com/ArrayZoneYour/react-model-todomvc)\n\n[⇧ back to top](#table-of-contents)\n\n### Model\n\nEvery model have their own state and actions.\n\n```typescript\nconst initialState = {\n  counter: 0,\n  light: false,\n  response: {} as {\n    code: number\n    message: string\n  }\n}\n\ntype StateType = typeof initialState\ntype ActionsParamType = {\n  increment: number\n  openLight: undefined\n  get: undefined\n} // You only need to tag the type of params here !\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    },\n    openLight: async (state, actions) => {\n      await actions.increment(1) // You can use other actions within the model\n      await actions.get() // support async functions (block actions)\n      actions.get()\n      await actions.increment(1) // + 1\n      await actions.increment(1) // + 2\n      await actions.increment(1) // + 3 as expected !\n      return { light: !state.light }\n    },\n    get: async () => {\n      await new Promise((resolve, reject) =>\n        setTimeout(() => {\n          resolve()\n        }, 3000)\n      )\n      return {\n        response: {\n          code: 200,\n          message: `${new Date().toLocaleString()} open light success`\n        }\n      }\n    }\n  },\n  state: initialState\n}\n\nexport default Model\n\n// You can use these types when use Class Components.\n// type ConsumerActionsType = getConsumerActionsType<typeof Model.actions>\n// type ConsumerType = { actions: ConsumerActionsType; state: StateType }\n// type ActionType = ConsumerActionsType\n// export { ConsumerType, StateType, ActionType }\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getState\n\nKey Point: [State variable not updating in useEffect callback](https://github.com/facebook/react/issues/14066)\n\nTo solve it, we provide a way to get the current state of model: getState\n\nNote: the getState method cannot invoke the dom changes automatically by itself.\n\n> Hint: The state returned should only be used as readonly\n\n```jsx\nimport { useStore, getState } from '../model/index.model'\n\nconst BasicHook = () => {\n  const [state, actions] = useStore('Counter')\n  useEffect(() => {\n    console.log('some mounted actions from BasicHooks')\n    return () =>\n      console.log(\n        `Basic Hooks unmounted, current Counter state: ${JSON.stringify(\n          getState('Counter')\n        )}`\n      )\n  }, [])\n  return (\n    <>\n      <div>state: {JSON.stringify(state)}</div>\n    </>\n  )\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### getActions\n\nYou can call other models' actions with getActions api\n\ngetActions can be used in both class components and functional components.\n\n```js\nimport { getActions } from './index.model'\n\nconst sharedActions = getActions('Shared')\nconst counterActions = getActions('Counter')\n\nconst model = {\n  state: {},\n  actions: {\n    crossModelCall: () => {\n      sharedActions.changeTheme('dark')\n      counterActions.increment(9)\n    }\n  }\n}\n\nexport default model\n```\n\n[⇧ back to top](#table-of-contents)\n\n## Advance Concept\n\n### immutable Actions\n\nThe actions use [immer](https://github.com/mweststrate/immer) produce API to modify the Store. You can return a producer in action.\n\nUsing function as return value can make your code cleaner when you modify the deep nested value.\n\nTypeScript Example\n\n```ts\n// StateType and ActionsParamType definition\n// ...\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: async (s, _, params) => {\n      // issue: https://github.com/Microsoft/TypeScript/issues/29196\n      // async function return produce need define type manually.\n      return (state: typeof s) => {\n        state.counter += params || 1\n      }\n    },\n    decrease: (s, _, params) => s => {\n      s.counter += params || 1\n    }\n  }\n}\n```\n\nJavaScript Example\n\n```js\nconst Model = {\n  actions: {\n    increment: async (s, _, params) => {\n      return state => {\n        state.counter += params || 1\n      }\n    }\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### SSR with Next.js\n\n`shared.model.ts`\n\n```ts\nconst initialState = {\n  counter: 0\n}\n\nconst Model: ModelType<StateType, ActionsParamType> = {\n  actions: {\n    increment: (state, _, params) => {\n      return {\n        counter: state.counter + (params || 1)\n      }\n    }\n  },\n  // Provide for SSR\n  asyncState: async context => {\n    await waitFor(4000)\n    return { counter: 500 }\n  },\n  state: initialState\n}\n```\n\n`_app.tsx`\n\n```tsx\nimport { models, getInitialState, Models } from '../model/index.model'\n\nlet persistModel: any\n\ninterface ModelsProps {\n  initialModels: Models\n  persistModel: Models\n}\n\nconst MyApp = (props: ModelsProps) => {\n  if ((process as any).browser) {\n    // First come in: initialModels\n    // After that: persistModel\n    persistModel = props.persistModel || Model(models, props.initialModels)\n  }\n  const { Component, pageProps, router } = props\n  return (\n    <Container>\n      <Component {...pageProps} />\n    </Container>\n  )\n}\n\nMyApp.getInitialProps = async (context: NextAppContext) => {\n  if (!(process as any).browser) {\n    const initialModels = context.Component.getInitialProps\n      ? await context.Component.getInitialProps(context.ctx)\n      await getInitialState() // get all model initialState\n      // : await getInitialState({ modelName: 'Home' }) // get Home initialState only\n      // : await getInitialState({ modelName: ['Home', 'Todo'] }) // get multi initialState\n      // : await getInitialState({ data }) // You can also pass some public data as asyncData params.\n    return { initialModels }\n  } else {\n    return { persistModel }\n  }\n}\n```\n\n`hooks/index.tsx`\n\n```tsx\nimport { useStore, getState } from '../index.model'\nexport default () => {\n  const [state, actions] = useStore('Home')\n  const [sharedState, sharedActions] = useStore('Shared')\n\n  return (\n    <div>\n      Home model value: {JSON.stringify(state)}\n      Shared model value: {JSON.stringify(sharedState)}\n      <button\n        onClick={e => {\n          actions.increment(33)\n        }}\n      >\n    </div>\n  )\n}\n```\n\n`benchmark.tsx`\n\n```tsx\n// ...\nBenchmark.getInitialProps = async () => {\n  return await getInitialState({ modelName: 'Todo' })\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### Middleware\n\nWe always want to try catch all the actions, add common request params, connect Redux devtools and so on. We Provide the middleware pattern for developer to register their own Middleware to satisfy the specific requirement.\n\n```tsx\n// Under the hood\nconst tryCatch: Middleware<{}> = async (context, restMiddlewares) => {\n  const { next } = context\n  await next(restMiddlewares).catch((e: any) => console.log(e))\n}\n\n// ...\n\nlet actionMiddlewares = [\n  tryCatch,\n  getNewState,\n  setNewState,\n  stateUpdater,\n  communicator,\n  devToolsListener\n]\n\n// ...\n// How we execute an action\nconst consumerAction = (action: Action) => async (params: any) => {\n  const context: Context = {\n    modelName,\n    setState,\n    actionName: action.name,\n    next: () => {},\n    newState: null,\n    params,\n    consumerActions,\n    action\n  }\n  await applyMiddlewares(actionMiddlewares, context)\n}\n\n// ...\n\nexport { ... , actionMiddlewares}\n```\n\n⚙️ You can override the actionMiddlewares and insert your middleware to specific position\n\n[⇧ back to top](#table-of-contents)\n\n## Other Concept required by Class Component\n\n### Provider\n\nThe global state standalone can not effect the react class components, we need to provide the state to react root component.\n\n```jsx\nimport { PureComponent } from 'react'\nimport { Provider } from 'react-model'\n\nclass App extends PureComponent {\n  render() {\n    return (\n      <Provider>\n        <Counter />\n      </Provider>\n    )\n  }\n}\n```\n\n[⇧ back to top](#table-of-contents)\n\n### connect\n\nWe can use the Provider state with connect.\n\nJavascript decorator version\n\n```jsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\n\nconst mapProps = ({ light, counter }) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter\n}) // You can map the props in connect.\n\n@connect(\n  'Home',\n  mapProps\n)\nexport default class JSCounter extends PureComponent {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(5)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n      </>\n    )\n  }\n}\n```\n\nTypeScript Version\n\n```tsx\nimport React, { PureComponent } from 'react'\nimport { Provider, connect } from 'react-model'\nimport { StateType, ActionType } from '../model/home.model'\n\nconst mapProps = ({ light, counter, response }: StateType) => ({\n  lightStatus: light ? 'open' : 'close',\n  counter,\n  response\n})\n\ntype RType = ReturnType<typeof mapProps>\n\nclass TSCounter extends PureComponent<\n  { state: RType } & { actions: ActionType }\n> {\n  render() {\n    const { state, actions } = this.props\n    return (\n      <>\n        <div>TS Counter</div>\n        <div>states - {JSON.stringify(state)}</div>\n        <button onClick={e => actions.increment(3)}>increment</button>\n        <button onClick={e => actions.openLight()}>Light Switch</button>\n        <button onClick={e => actions.get()}>Get Response</button>\n        <div>message: {JSON.stringify(state.response)}</div>\n      </>\n    )\n  }\n}\n\nexport default connect(\n  'Home',\n  mapProps\n)(TSCounter)\n```\n\n[⇧ back to top](#table-of-contents)\n\n## FAQ\n\n### How can I disable the console debugger?\n\nJust remove consoleDebugger middleware.\n\n```typescript\nimport { actionMiddlewares } from 'react-model'\n// Find the index of middleware\nconst consoleDebuggerMiddlewareIndex = actionMiddlewares.indexOf(\n  middlewares.consoleDebugger\n)\n// Remove it\nactionMiddlewares.splice(consoleDebuggerMiddlewareIndex, 1)\n```\n","readmeFilename":"README.md","homepage":"https://github.com/byte-fe/react-model#readme","repository":{"type":"git","url":"git+https://github.com/byte-fe/react-model.git"},"bugs":{"url":"https://github.com/byte-fe/react-model/issues"}}