{"_id":"@alinnert/tstate","_rev":"4-9ad11c9bd8ebb551cd0dd5130f90fc9c","name":"@alinnert/tstate","dist-tags":{"latest":"1.0.3"},"versions":{"1.0.0":{"name":"@alinnert/tstate","version":"1.0.0","license":"MIT","main":"dist/index.js","typings":"dist/index.d.ts","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test --passWithNoTests","lint":"tsdx lint","prepare":"tsdx build"},"peerDependencies":{"react":">=16"},"husky":{"hooks":{"pre-commit":"tsdx lint"}},"author":{"name":"Andreas Linnert"},"module":"dist/tstate.esm.js","publishConfig":{"access":"public"},"devDependencies":{"@types/jest":"^25.1.2","@types/react":"^16.9.19","@types/react-dom":"^16.9.5","@typescript-eslint/eslint-plugin":"^2.19.2","@typescript-eslint/parser":"^2.19.2","eslint":"^6.8.0","eslint-config-standard-with-typescript":"^13.0.0","eslint-plugin-import":"^2.20.1","eslint-plugin-node":"^11.0.0","eslint-plugin-promise":"^4.2.1","eslint-plugin-standard":"^4.0.1","husky":"^4.2.3","react":"^16.12.0","react-dom":"^16.12.0","tsdx":"^0.12.3","tslib":"^1.10.0","typescript":"^3.7.5"},"gitHead":"fc6a913c4f6a2c76c0ec93cd2138958a58971f70","description":"This is a very simple data store/state management library, writen in TypeScript. It also comes with a React hook.","_id":"@alinnert/tstate@1.0.0","_nodeVersion":"13.6.0","_npmVersion":"6.13.0","dist":{"integrity":"sha512-L+ABsHmLmGJQThpNpnUmnYQpyptmkkCXEjTjHG+Qc0lah54A+MvYackwwAdPNrB8/elpOv0PrJnz3POfWClTgg==","shasum":"75da15c92c175ed455417477a0ed2989bfb5995f","tarball":"https://registry.npmjs.org/@alinnert/tstate/-/tstate-1.0.0.tgz","fileCount":12,"unpackedSize":92630,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeRcZACRA9TVsSAnZWagAAgUQP/jyk3cWjmr6rkgyFC42V\nK8QWYGRglTJeBZqg3RRYAVSa7HiwFK5dDP8DxMm3uEORCN/d+4U2qTQTOAJg\nSQWDP65f/V7LL3diAEIjduZdzKFDm3jKM7Jd8RVxBGXzdBejSk/8/jHdLWb2\nsGUswsK3S/qEIZWwoTcGlwE36uZ5Pb7MKuw6WYWQwTKyoKqiFYCwFDGn0oaa\nsrGE/PcKMGEif5Z1E8dWVv5cMjF7OMIIwrGSySEtSgOGHD+1fyWIHdslgm6I\nOSbarWucd9Fju+V13gndH1ecqVhUiHwtvJjif71+1cL/cO9ztDGxIY/oLDwJ\n/Kfk91DgXzHCXc1GQe805spokp728H68F8krLhzR4CQiFwnD7ptQGIDnQAK6\nM591vvntbrANcb+2OktlJqvsfUODDeFvTHQiZylDSU307IiTPg1tM47O9D8Y\n1ddIm5ai1ECo4dX9L8sTm8l3EYqup5At8xTf9S9RFxcJKW1ER3BJywRb+uRO\nxwR5AUVnFjn5RGvUObQsJiVoxE1PYQzGzywWXvD1pe9jfI2XXDD33XTKZmD+\nXMDLveuMYzBivX2B3qJob8hRqyP5rfRAT5TmkNbbSkJb6qXaDZTL78bzaLKf\nvP5pZAdNRNJUbnd7mKQ35sPG34vO872gFYjp8qmXn10AsSLL9lb7G+6BvqH/\n75if\r\n=Yia4\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFQwayAL159Y59BtIWQkZ0BBlcI5++9+T4/wQyXMlmStAiEApgLuiArMU3Tf3PJscsCbasqtPpRBF1vvnrmJUTk2M1c="}]},"maintainers":[{"name":"alinnert","email":"alinnert@live.de"}],"_npmUser":{"name":"alinnert","email":"alinnert@live.de"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tstate_1.0.0_1581631039704_0.6100261219508099"},"_hasShrinkwrap":false},"1.0.1":{"name":"@alinnert/tstate","version":"1.0.1","license":"MIT","main":"dist/index.js","typings":"dist/index.d.ts","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test --passWithNoTests","lint":"tsdx lint","prepare":"tsdx build"},"peerDependencies":{"react":">=16"},"husky":{"hooks":{"pre-commit":"tsdx lint"}},"author":{"name":"Andreas Linnert"},"module":"dist/tstate.esm.js","publishConfig":{"access":"public"},"devDependencies":{"@types/jest":"^25.1.2","@types/react":"^16.9.19","@types/react-dom":"^16.9.5","@typescript-eslint/eslint-plugin":"^2.19.2","@typescript-eslint/parser":"^2.19.2","eslint":"^6.8.0","eslint-config-standard-with-typescript":"^13.0.0","eslint-plugin-import":"^2.20.1","eslint-plugin-node":"^11.0.0","eslint-plugin-promise":"^4.2.1","eslint-plugin-standard":"^4.0.1","husky":"^4.2.3","react":"^16.12.0","react-dom":"^16.12.0","tsdx":"^0.12.3","tslib":"^1.10.0","typescript":"^3.7.5"},"gitHead":"d02a48e06d2efa153d6513edbfacec9c571cce63","description":"This is a very simple data store/state management library, writen in TypeScript. It also comes with a React hook.","_id":"@alinnert/tstate@1.0.1","_nodeVersion":"12.16.1","_npmVersion":"6.13.7","dist":{"integrity":"sha512-Fk5iDJ1NV23zjwF+giOVCuonmkQ/uO/mXO58ysO6I78rNdZSexw8rRgq/Q6bluOl3075vL5uwuAwx8er6k1Efw==","shasum":"223a017bf21c745adb3bc066162ee2204e442738","tarball":"https://registry.npmjs.org/@alinnert/tstate/-/tstate-1.0.1.tgz","fileCount":13,"unpackedSize":20048,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeTWCYCRA9TVsSAnZWagAAIOMP/R/Z5okruZLcmIMr+2rZ\nrypRv+RoHPpTuPWl6VB7IT3ImEdJhnD+eeSlgZFPHylJP8IZkTYDpzq6og2j\nD18o69+ls+6sJOuu+EKbO4Bv0rkZjX/L0KRBtnIB9Iu/J1FJ+i+Wu9zBnOkc\nnmYztE31OSPMbNsojqH0C0PxqUdtn9mEEzlytbV/eiB6rVMHAJ4XG2lbglKN\nATW2dYAk4bwrwD2fBYePYc6b+2GMczdPi0H35fnaFUXfJxutJgQfu8B5/ldQ\niVzZ94RI1OiHoC/1wk6lLrdNfNg63+tn78DRxaAe7p48o8y5tH5ctJipEAsp\nZb0o6o4vzHU8usLhjMZY8ZJHJhUZ37/jt+Etu+QYaGXxEFzWPaDeEDJtw1Nt\n2RNsr+iyxRRWAC2WXpSbK3At3kJXsgxF/6Ox6ypY8f5FtMRtbiakbimh3mXP\n7bvCc51gUUdv5F8wD71174upEFOc7mda04LNbBWa6XWAe6JuZCLrpH1EBin7\nh6Bxgui9tLEqMxi50v3mNRjXYmGucMI91159l1xC6kG5Wuk24JEFxi76ENdb\nIlqrP8ejh5GVJ01Vkt14PbDINX8AbuWoGSGfsKV+qWzBnyuIN2NTwYJTRn7y\n9QivUNepvtJIq4AfU3tIdn6AwIGca0MDgLYsVDpm3ZWtv0sStFjTZKeG+inK\nEL9C\r\n=NB44\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDjcYc87ofkPZ+KLTQtgZ9GOu0rM41UFHmcQXLkv6GSAwIhAMU2j8Ott7kkkfRYwVoBBV6bm1HTd7+xf/0otv1PJSPu"}]},"maintainers":[{"name":"alinnert","email":"alinnert@live.de"}],"_npmUser":{"name":"alinnert","email":"alinnert@live.de"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tstate_1.0.1_1582129303713_0.2645809513887918"},"_hasShrinkwrap":false},"1.0.2":{"name":"@alinnert/tstate","version":"1.0.2","license":"MIT","main":"dist/index.js","typings":"dist/index.d.ts","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test --passWithNoTests","lint":"tsdx lint","prepare":"tsdx build"},"peerDependencies":{"react":">=16"},"husky":{"hooks":{"pre-commit":"tsdx lint"}},"author":{"name":"Andreas Linnert"},"module":"dist/tstate.esm.js","publishConfig":{"access":"public"},"devDependencies":{"@types/jest":"^25.1.4","@types/react":"^16.9.23","@types/react-dom":"^16.9.5","@typescript-eslint/eslint-plugin":"^2.24.0","@typescript-eslint/parser":"^2.24.0","eslint":"^6.8.0","eslint-config-standard-with-typescript":"^14.0.0","eslint-plugin-import":"^2.20.1","eslint-plugin-node":"^11.0.0","eslint-plugin-promise":"^4.2.1","eslint-plugin-standard":"^4.0.1","husky":"^4.2.3","react":"^16.13.0","react-dom":"^16.13.0","tsdx":"^0.12.3","tslib":"^1.11.1","typescript":"^3.8.3"},"gitHead":"e58a044a0cd1751148504e0100b1d27ee00a20d5","description":"This is a very simple data store/state management library, writen in TypeScript. It also comes with a React hook.","_id":"@alinnert/tstate@1.0.2","_nodeVersion":"12.16.1","_npmVersion":"6.13.7","dist":{"integrity":"sha512-8zakc6z69OPC0AgxsCo4aMR+IQ/NI/NIvAgNQv5DQLz0kXs1Kg8fvXLFyp31E9r3HCmbQlYuMKJLZH5PihJ5lw==","shasum":"2d899a8de25c1a6c75a09e8f922b6535eb3df94d","tarball":"https://registry.npmjs.org/@alinnert/tstate/-/tstate-1.0.2.tgz","fileCount":13,"unpackedSize":20457,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJecKwbCRA9TVsSAnZWagAALsQP/3TE3SrVoAwMP8iPcQkk\nxDk8UcPgGFlJU3Cgo/Zfgb/ar/39DvOluELCtThwgouIsPlU2OQfeyRCud0D\nxJWOFYGEvz7kZ6mj8PML7ZESGkpOQ51Cx40rfpuzKtC4kXQ0yBkv6jA88pFl\nA5JkMg92spCvWZOkksMFoTV4xaPY5Fz+a+t7AEa1i4vda8OEW+VpMhA/H+pg\nznjmWH4EIlEFp36ZklWZF/Is0tCSHqq+OGdgSgu7r97FMHyEKwDMy9cuoz/N\nXgNewKZ1NH9xM5AOq5KPweCNkvDukkZKuCgYk2romyEyrcuv6/5W8/cCIBrs\n0Lzmg/fQE987cXIrislBkVHgSlhpkOtv8rlqp56VYYTbH2QGU33yqPzyA+ZC\nqmOZ8PX1R9wXvySm2a3ZZtm8+C60iLW96RjeAu0+BQVCKjkZnMPhM8eIEA8E\nO3Yoa4moWc17WoxpjgfJ87QyDRHr/Qk9Iu2n9YnBlKV0X1avYQq+1J/bKfsv\noAcYhhXd6pGTjZC0Di6UXdveOecTlzLynYc8yGYe+MqOtD1TOY98g17zQUYk\nUkd1dyAHN9wJwXdwjJu7GEK13GUacpL+MLsHRHaKcCkfwDxC/IN38RSFMbxa\nTB8WfyVajnCpnYDEM5Hvl+FgPO3x/Fm9EIM0AUtjEEKpFQylTwzwfC1UziRs\n3mmE\r\n=YUwp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCVzyi+ZB7HkbD2e0j/quWi+KB6b92ds5QvDdEfzrBipQIhALUVaac87iipyWrS7e82zoV/00G2c8G637Xo7Cn+cgzg"}]},"maintainers":[{"name":"alinnert","email":"alinnert@live.de"}],"_npmUser":{"name":"alinnert","email":"alinnert@live.de"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tstate_1.0.2_1584442395085_0.24319535919721913"},"_hasShrinkwrap":false},"1.0.3":{"name":"@alinnert/tstate","version":"1.0.3","license":"MIT","main":"dist/index.js","typings":"dist/index.d.ts","scripts":{"start":"tsdx watch","build":"tsdx build","test":"tsdx test --passWithNoTests","lint":"tsdx lint","prepare":"tsdx build"},"peerDependencies":{"react":">=16"},"husky":{"hooks":{"pre-commit":"tsdx lint"}},"author":{"name":"Andreas Linnert"},"module":"dist/tstate.esm.js","publishConfig":{"access":"public"},"devDependencies":{"@types/jest":"^25.1.4","@types/react":"^16.9.23","@types/react-dom":"^16.9.5","@typescript-eslint/eslint-plugin":"^2.24.0","@typescript-eslint/parser":"^2.24.0","eslint":"^6.8.0","eslint-config-standard-with-typescript":"^14.0.0","eslint-plugin-import":"^2.20.1","eslint-plugin-node":"^11.0.0","eslint-plugin-promise":"^4.2.1","eslint-plugin-standard":"^4.0.1","husky":"^4.2.3","react":"^16.13.0","react-dom":"^16.13.0","tsdx":"^0.12.3","tslib":"^1.11.1","typescript":"^3.8.3"},"gitHead":"9f1246d737b78b53f6538c21bd695ec6d163835e","description":"This is a very simple data store/state management library, writen in TypeScript. It also comes with a React hook.","_id":"@alinnert/tstate@1.0.3","_nodeVersion":"12.16.1","_npmVersion":"6.13.7","dist":{"integrity":"sha512-7DDqRuARjA/lhNqZUbDkPgTlNPh0mK9AZZAK7rUncCR6p38jtKBxy9nbJdoY1bbo3LtezN2NSYpvuYDYFVMKrg==","shasum":"94932f34d4018d6a01144d3a99d77741a4ee1d92","tarball":"https://registry.npmjs.org/@alinnert/tstate/-/tstate-1.0.3.tgz","fileCount":13,"unpackedSize":20629,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJecK+4CRA9TVsSAnZWagAAT40P/1+/T9t0oT+hvNXwfEx2\nr1kVQywpqvP0ZUyhmY5+/AALGF4xavwJQIUwLEHc5xmbqcIsV9e07OW1IL4Y\npMSVSdgOcxoGx40YPF9gmkmexEYaZR5HWi3v52tpm2xCLOjjWTlhdh7vnLGI\nkOZfZpTUFqxQxnhIDqY8HJTbYnBW8vOAkpEj5R6TFycspT/Ed2N3NaKjYzG9\n9XOFZwbXuRMirxKUJtGZw5VSWG1/lHgn6EZTh8PgSk1sq16VSNOw7jTZwk6K\nV/hkqlbOWx7aXZSDz7ExGOX0p1RKqDHTZLcaf9ODnCPb+eWa8TgEb9YtSjMe\nIEy13HT2ONEjgHn7B5NKdMF6NXzLa/q31CZsbhmlh3pSm9lzstq7LQNMogHV\naP8I1kyHKVA43Hlk89i7vU3Px9woCghOo//QNuWFHowI7aSKykLJuZJuXwS2\nA8SNU0ccheJ1uBW6FeXKWW3meNQjidJNBq9RsoBS54oLlh7NJ5DRotC8flES\n7S7AzolTjawMJc6JAwhca30Aw1B5r7T0/vsBpmQMTSdDAkeb+LYQENItZn6b\n6tUcVKoS+Cdt+uryC7zzwRU7dTfrVoOG9Fy/9miJZOAHRnsoDNOgUJCYVCHA\nhg/dhiguDyZUK80IWz4zzgpdsR4AqQ+03H6nOHWi3FkR0ySbihLlb4IZVwxA\ncwIL\r\n=j8vN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCID794hTX/bZUE1h91bOrQb4ZVdhD3xYlXrx/W5k07XTKAiABMBSB/8wzsmWVF/D8NVsI2Sp03eDZ4bMFfEO3C1Y1Xg=="}]},"maintainers":[{"name":"alinnert","email":"alinnert@live.de"}],"_npmUser":{"name":"alinnert","email":"alinnert@live.de"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tstate_1.0.3_1584443320067_0.4761876077437286"},"_hasShrinkwrap":false}},"time":{"created":"2020-02-13T21:57:19.677Z","1.0.0":"2020-02-13T21:57:19.870Z","modified":"2022-04-04T13:26:11.848Z","1.0.1":"2020-02-19T16:21:43.857Z","1.0.2":"2020-03-17T10:53:15.231Z","1.0.3":"2020-03-17T11:08:40.325Z"},"maintainers":[{"name":"alinnert","email":"alinnert@live.de"}],"description":"This is a very simple data store/state management library, writen in TypeScript. It also comes with a React hook.","author":{"name":"Andreas Linnert"},"license":"MIT","readme":"# TState\r\n\r\nThis is a very simple data store/state management library, writen in TypeScript. It also comes with a React hook.\r\n\r\n## Why?\r\n\r\nWhen I started learning React (after making some projects with Vue) I was looking for a data store solution. The two big ones in the React ecosystem are *Redux* and *MobX*. But I think both have flaws in my opinion:\r\n\r\nRedux is bulky (in terms of boilerplate code) and the necessary type parameters for the `useSelector<T, U>()` hook are awkward but necessary. Also, there's another library necessary to write async actions.\r\n\r\nThe API of MobX just feels like its all over the place. This gives me a hard time getting started with it. There are many ways to do the same thing, including decorators which aren't supported by `create-react-app` - for a good reason.\r\n\r\nThen I stumbled over one of those \"You probably don't need Redux\" articles. It made me think. So I created a module that fetches data from a server, stores it (+ some status information) in variables and connected that modules to a React component via a hook. I made another one for a different resource on the same server. Now I was able to identify the repeating parts and abstracted them away into a new module. TState is the result of that effort. It turned out to be less than 50 LOC which was really surprising.\r\n\r\n## What are the benefits?\r\n\r\n- It is written with TypeScript in mind. It's super convenient to type your stores.\r\n- The API surface is tiny, which makes it easy to learn.\r\n- It \"supports\" async actions out of the box, by not limiting to sync actions in the first place.\r\n- No wrapper component needed for React.\r\n- Also, React support is separated from the core implementation, but included. So, you can use it basically anywhere.\r\n\r\n## Are there drawbacks?\r\n\r\n- A store root **must** be an object, no arrays and other non-object types are supported. Its properties can be of any type, though.\r\n- Currently, there's no support for computed values. (May be added later)\r\n- No time-travel debugging.\r\n\r\n## How do I install it?\r\n\r\n~~~ bash\r\n$ npm install tstate\r\n~~~\r\n\r\n## How do I use it?\r\n\r\nFirst of all you create your store.\r\n\r\n**newsStore.ts**\r\n\r\n~~~ ts\r\nimport { createStore, createReactHook } from './createStore.ts'\r\n\r\n// STEP 1: create interfaces that describe your store\r\ninterface News {\r\n  title: string\r\n  body: string\r\n}\r\n\r\ninterface NewsStore {\r\n  items: News[]\r\n  loading: boolean\r\n  error: boolean\r\n}\r\n\r\n// STEP 2: create the initial state\r\n// The state MUST be an object. Simple values like\r\n// numbers or strings but also arrays are not supported.\r\n// Wrapping the state object in a function is recommended\r\n// if you want to reuse the initial state later,\r\n// like in a 'reset' mutation.\r\nfunction getInitialState (): NewsStore {\r\n  return {\r\n    items: [],\r\n    loading: false,\r\n    error: false\r\n  }\r\n}\r\n\r\n// STEP 3: create the store\r\nconst newsStore = createStore(getInitialState())\r\n\r\n// STEP 4A (React): create the React hook and export it\r\nexport const useNewsStore = createReactHook(newsStore)\r\n\r\n// STEP 4B (No React): subscribe to the store\r\n// You will receive the latest state immediately after subscribing.\r\nconst unsubscribeNewsStore = newsStore.subscribe((newState) => {\r\n  doSomethingWith(newState)\r\n})\r\n\r\n// Unsubscribe if you're finished with your business.\r\n// Useful for component frameworks like React.\r\n// This is what the built-in React hook actually does.\r\nunsubscribeNewsStore()\r\n\r\n// You can also access the current state. This returns the\r\n// store object. In this case it's of type `NewsStore`.\r\nnewsStore.state\r\n\r\n// STEP 5: write some (maybe async) functions to change your store\r\n// Pro Tip: You can put all calls to `newsStore.set()` in separate\r\n// (\"mutation\") functions to avoid repeating the entire state object.\r\nexport async function loadNews (): Promise<void> {\r\n  newsStore.set({ loading: true, error: false })\r\n  \r\n  try {\r\n    const result = axios.get('/news')\r\n    newsStore.set({ items: result.data, loading: false, error: false })\r\n  } catch {\r\n    newsStore.set({ loading: false, error: true })\r\n  }\r\n}\r\n~~~\r\n\r\nNow you can use this hook and the functions in your components\r\n\r\n**NewsList.tsx**\r\n\r\n~~~ tsx\r\nimport React, { FC } from 'react'\r\nimport { useNewsStore, loadNews } from '../stores/newsStore'\r\n\r\nexport const NewsList: FC = () => {\r\n  // Destructure the top-level props from the store.\r\n  // The fun part is: The types get inferred all the through,\r\n  // starting at the interface \"NewsStore\".\r\n  // The type of `items` is `News[]`\r\n  // The type of `items[0].title` is `string`.\r\n  const { items, loading, error } = useNewsStore()\r\n  \r\n  useEffect(() => {\r\n    // Fetch news from the server when the component mounts.\r\n    // Just call the function directly. No fancy stuff needed.\r\n    loadNews()\r\n  }, [])\r\n  \r\n  function handleRefreshClick () {\r\n    // If the user clicks the \"Refresh\" button, load the news again.\r\n    loadNews()\r\n  }\r\n\r\n  return (\r\n    <div className=\"news-list\">\r\n      <button onClick={handleRefreshClick}>Refresh</button>\r\n    \r\n      {loading ? <div>Loading...</div> : null}\r\n      {error ? <div>An error occured.</div> : null}\r\n      {items.length === 0 ? <div>There are no news.</div> : null}\r\n      \r\n      {items.map(item => (\r\n        <article>\r\n          <h2>{item.title}</h2>\r\n          <p>{item.body}</p>\r\n        </article>\r\n      ))}\r\n    </div>\r\n  )\r\n}\r\n~~~\r\n\r\nThat's all there is to it!\r\n","readmeFilename":"README.md"}