{"id":13394066,"url":"https://github.com/leebyron/react-loops","last_synced_at":"2025-05-15T16:05:57.121Z","repository":{"id":40005605,"uuid":"178903387","full_name":"leebyron/react-loops","owner":"leebyron","description":"React Loops works with React Hooks as part of the React Velcro Architecture","archived":false,"fork":false,"pushed_at":"2019-04-30T19:28:52.000Z","size":195,"stargazers_count":1162,"open_issues_count":2,"forks_count":20,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-05-11T04:07:56.765Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leebyron.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-04-01T16:28:00.000Z","updated_at":"2025-04-08T15:58:28.000Z","dependencies_parsed_at":"2022-06-26T07:31:25.959Z","dependency_job_id":null,"html_url":"https://github.com/leebyron/react-loops","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leebyron%2Freact-loops","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leebyron%2Freact-loops/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leebyron%2Freact-loops/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leebyron%2Freact-loops/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leebyron","download_url":"https://codeload.github.com/leebyron/react-loops/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254374461,"owners_count":22060611,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T17:01:07.816Z","updated_at":"2025-05-15T16:05:57.102Z","avatar_url":"https://github.com/leebyron.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","Components"],"sub_categories":["Misc"],"readme":"\u003cimg align=\"right\" src=\"assets/hook-and-loop.gif\"\u003e\n\n# React Loops — _React Velcro Architecture_\n\n[![Build Status](https://travis-ci.com/leebyron/react-loops.svg?branch=master)](https://travis-ci.com/leebyron/react-loops) [![Coverage Status](https://coveralls.io/repos/github/leebyron/react-loops/badge.svg?branch=master)](https://coveralls.io/github/leebyron/react-loops?branch=master)\n\nReact Loops work alongside React Hooks as part of the novel _React Velcro_\narchitecture for building sticky, secure user interfaces that don't come apart\nunder pressure.\n\n[Version Changelog](https://github.com/leebyron/react-loops/releases)\n\n## Get started with Velcro by installing React Loops!\n\nInstall with yarn or npm.\n\n```sh\nyarn add react-loops\n```\n\nAnd import into your Javascript.\n\n```js\nimport { For } from 'react-loops'\n```\n\nReact Loops comes ready with both Flow and TypeScript types for high quality\nintegration into codebases that use these tools.\n\n## For-of Loops\n\nUse the props `of` to provide the list and `as` to provide an element for\neach item in the list. The `of` prop accepts Arrays, Array-likes,\nand Iterables (such as [`Map`], [`Set`], and [Immutable.js]).\n\n[`Map`]: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map\n[`Set`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set\n[Immutable.js]: https://immutable-js.github.io/immutable-js/\n\n```js\nimport { For } from 'react-loops'\n\nfunction Bulleted({ list }) {\n  return (\n    \u003cul\u003e\n      \u003cFor of={list} as={item =\u003e\n        \u003cli\u003e{item}\u003c/li\u003e\n      }/\u003e\n    \u003c/ul\u003e\n  )\n}\n```\n\nOr provide a \"render prop\" function as a child.\n\n```js\nimport { For } from 'react-loops'\n\nfunction Bulleted({ list }) {\n  return (\n    \u003cul\u003e\n      \u003cFor of={list}\u003e\n        {item =\u003e\n          \u003cli\u003e{item}\u003c/li\u003e\n        }\n      \u003c/For\u003e\n    \u003c/ul\u003e\n  )\n}\n```\n\n## For-in Loops\n\nUse the prop `in` to provide an Object instead of an Array or Iterable.\n\n```js\nimport { For } from 'react-loops'\n\nfunction BulletedDefinitions({ terms }) {\n  return (\n    \u003cul\u003e\n      \u003cFor in={terms} as={(item, {key}) =\u003e\n        \u003cli\u003e{key}: {item}\u003c/li\u003e\n      }/\u003e\n    \u003c/ul\u003e\n  )\n}\n```\n\n## Loop empty conditions\n\nA common pattern when rendering a collection is to render a special case when\nthe collection is empty. Optionally provide an `ifEmpty` prop to handle this\ncase for both `\u003cFor in\u003e` and `\u003cFor of\u003e` loops.\n\nThe `ifEmpty` prop accepts anything renderable (strings, numbers, JSX) or a\n*function* which returns anything renderable.\n\n```js\nimport { For } from 'react-loops'\n\nfunction BulletedWithFallback({ list }) {\n  return (\n     \u003cul\u003e\n      \u003cFor of={list} ifEmpty={\u003cem\u003eNothing here!\u003c/em\u003e}\u003e\n        {item =\u003e\n          \u003cli\u003e{item}\u003c/li\u003e\n        }\n      \u003c/For\u003e\n    \u003c/ul\u003e\n  )\n}\n```\n\n## Loop iteration metadata\n\nAccess additional information about each iteration by destructuring the\nsecond callback argument:\n\n- `index`: A number from 0 to the length of the list\n- `length`: The length of the list\n- `key`: The key for this item in the list, same as `index` for Arrays\n         but string Object properties for `in` loops\n- `isFirst`: True for the first iteration\n- `isLast`: True for the last iteration\n\n```js\nimport { For } from 'react-loops'\n\nfunction BulletedSentence({ list }) {\n  return (\n    \u003cul\u003e\n      \u003cFor of={list} as={(item, { isLast }) =\u003e\n        \u003cli\u003e{isLast \u0026\u0026 \"and \"}{item}\u003c/li\u003e\n      }/\u003e\n    \u003c/ul\u003e\n  )\n}\n```\n\n## React Keys \u0026 Reorderable Collections\n\nReact Loops provides a `key` prop automatically on each child by default (by\nusing the `{ key }` loop iteration metadata). This is a great default if your\ncollection will not later reorder and an ergonomic improvement over your trained muscle memory of adding `key={i}` to every `list.map()` return value.\n\nHowever, reorderable collections should still directly provide the `key` prop on\nthe element returned from the loop callback. Read more about [Lists and Keys](https://reactjs.org/docs/lists-and-keys.html) in the React documentation.\n\n```js\nimport { For } from 'react-loops'\n\nfunction BulletedReorderable({ list }) {\n  return (\n    \u003cul\u003e\n      \u003cFor of={list} as={item =\u003e\n        \u003cli key={item.id}\u003e{item.label}\u003c/li\u003e\n      }/\u003e\n    \u003c/ul\u003e\n  )\n}\n```\n\n\n## What is _React Velcro_?\n\nOnly the newest, coolest, most blazing fast React architecture out there!\n\nReact Hooks has been an exciting development in the evolution of React, but it\nfelt like it was only half of the story. _React Loops_ completes the gripping\npicture by providing React's missing control-flow operators via JSX elements.\n\nThe _React Velcro_ architecture was announced by [@leebyron](https://github.com/leebyron/) on [April 1st, 2019](https://twitter.com/leeb/status/1112867350389219328).\n\n### Is this a Joke?\n\nTake a look at this side by side with the old looping pattern and you tell me ([hint](https://media.giphy.com/media/l2SqbYoAwd3KK1wli/giphy.gif)).\n\n\u003cimg src=\"assets/loops-vs-mapkeys.png\"\u003e\n\n### But isn't this a React anti-pattern? Just go use Angular or Vue?\n\nYes, React Loops is directly inspired by Angular and Vue. It's also directly\ninspired by older XML component syntax like XSLT, JSTL, and E4X. These\ntechnologies all have their drawbacks, however we should not abandon all aspects\nof these ideas.\n\nReact Loops are not an anti-pattern. `array.forEach()` is not an anti-pattern\ndespite the existence of the `for..of` loop and neither is `\u003cFor\u003e`. React\nLoops follows React's model of components as encapsulation of behavior and\nstate. It uses the \"render prop\" pattern, like\n[react-router](https://github.com/ReactTraining/react-router)'s  `\u003cRoute\u003e` component, itself reminiscent of XSLT.\n\nReact considers Angular (and Vue) directives as anti-patterns not because\nthey emulate loops or control flow. It is because they affect _scope_ in ways\nthat removes the ability to use plain Javascript, requires a template\nlanguage, and makes using other tools like ESLint difficult. They also are\nimplemented as attributes (props) on any element which complicates type-checking\nand implementation.\n\nReact Loops avoids these drawbacks by providing `\u003cFor\u003e` as a specific component\nwith a clear signature and callback functions to produce each element for clear,\n\"just Javascript,\" scoping rules avoiding the need for template languages or\nadditional compilation.\n\nTry React Loops in your project, you just might like it!\n\n### Are there any other libraries supporting that _React Velcro_ architecture?\n\n_*Yes*_\n\n* [babel-plugin-jsx-control-statements](https://www.npmjs.com/package/babel-plugin-jsx-control-statements) is a Babel plugin with many control statements.\n  \u003e Its `\u003cFor\u003e` component suffers from some of the problems described above, _caveat emptor_.\n* [react-condition](https://github.com/andrewfluck/react-condition) contains the old `\u003cIf\u003e`, `\u003cElse\u003e`, and `\u003cElseIf\u003e` statements from this library, as well as some new ones such as `\u003cSwitch\u003e`, `\u003cCase\u003e`, and `\u003cDefault\u003e`.\n* [react-for](https://github.com/MJez29/react-for) is a predecessor and a very similar idea which includes other variants of loops.\n* [react-listable](https://github.com/victorvoid/react-listable) is a predecessor of this idea which includes `\u003col\u003e` and `\u003cul\u003e` components.\n\n## Contributing \u0026 License\n\nContributions are welcome from all who follow the community\n[code of conduct](https://www.contributor-covenant.org/version/1/4/code-of-conduct).\n\n  1. [Fork](https://guides.github.com/activities/forking/) this repository\n  2. `yarn install`\n  3. Make your change in a [branch](https://help.github.com/en/articles/about-branches)\n  4. Ensure your change includes any relevant tests, type definitions\n     (TypeScript and Flow), and documentation.\n  5. `yarn test`\n  6. Create a [pull request](https://help.github.com/en/articles/creating-a-pull-request-from-a-fork)\n\n### React Loops is provided under the MIT license:\n\nCopyright 2019 Lee Byron\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleebyron%2Freact-loops","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleebyron%2Freact-loops","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleebyron%2Freact-loops/lists"}