{"id":17951727,"url":"https://github.com/joshwcomeau/react-collection-helpers","last_synced_at":"2025-03-25T00:31:33.819Z","repository":{"id":65473144,"uuid":"79040564","full_name":"joshwcomeau/react-collection-helpers","owner":"joshwcomeau","description":"A suite of composable utility components to manipulate collections.","archived":false,"fork":false,"pushed_at":"2017-01-31T13:18:20.000Z","size":736,"stargazers_count":106,"open_issues_count":1,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-18T05:11:55.236Z","etag":null,"topics":["arrays","components","functional-programming","react","reactjs"],"latest_commit_sha":null,"homepage":"https://joshwcomeau.github.io/react-collection-helpers/demo/dist/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joshwcomeau.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-15T15:20:09.000Z","updated_at":"2024-07-10T20:53:21.000Z","dependencies_parsed_at":"2023-01-25T12:01:26.168Z","dependency_job_id":null,"html_url":"https://github.com/joshwcomeau/react-collection-helpers","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshwcomeau%2Freact-collection-helpers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshwcomeau%2Freact-collection-helpers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshwcomeau%2Freact-collection-helpers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshwcomeau%2Freact-collection-helpers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joshwcomeau","download_url":"https://codeload.github.com/joshwcomeau/react-collection-helpers/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245377920,"owners_count":20605374,"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":["arrays","components","functional-programming","react","reactjs"],"created_at":"2024-10-29T09:50:12.373Z","updated_at":"2025-03-25T00:31:33.436Z","avatar_url":"https://github.com/joshwcomeau.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# React Collection Helpers\n#### A suite of composable utility components to manipulate collections.\n\n[![Travis][build-badge]][build]\n[![npm package][npm-badge]][npm]\n[![Coveralls][coveralls-badge]][coveralls]\n\n\n\n## Quick Example\n\n```jsx\nimport { Filter, Sort, First } from 'react-collection-helpers';\n\nconst users = [\n  { id: 'a', name: 'Harry', lastMessagedAt: '2016-03-14T15:00', isOnline: true },\n  { id: 'b', name: 'Bob', lastMessagedAt: '2017-01-20T12:00', isOnline: false },\n  { id: 'c', name: 'Molly', lastMessagedAt: '2013-01-02T03:04', isOnline: false },\n  { id: 'd', name: 'Karrin', lastMessagedAt: '2017-01-12T11:05', isOnline: true },\n  { id: 'e', name: 'Thomas', lastMessagedAt: '2014-03-04T13:37', isOnline: true },\n]\n\nconst UserList = ({ users }) =\u003e (\n  \u003cFilter collection={users} predicate={{ isOnline: true }}\u003e\n    \u003cSort comparator=\"lastMessagedAt\"\u003e\n      \u003cFirst num={4}\u003e\n        {user =\u003e \u003cdiv key={user.id}\u003e{user.name}\u003c/div\u003e}\n      \u003c/First\u003e\n    \u003c/Sort\u003e\n  \u003c/Filter\u003e\n)\n\nReactDOM.render(\n  \u003cUserList users={users}\u003e,\n  document.querySelector('#root')\n)\n\n/*\n  Renders:\n\n  \u003cdiv\u003e\n    \u003cdiv\u003eKarrin\u003c/div\u003e\n    \u003cdiv\u003eHarry\u003c/div\u003e\n    \u003cdiv\u003eThomas\u003c/div\u003e\n  \u003c/div\u003e\n*/\n```\n\n\n\n\n## Live Demo\n\n**[Play with a live demo.](https://joshwcomeau.github.io/react-collection-helpers/demo/dist/)**\n\n\n\n## Table of Contents\n\n- [Features](#features)\n- [Drawbacks](#drawbacks)\n- [Installation](#installation)\n- [Feedback Wanted](#feedback-wanted)\n- [Usage](#usage)\n- [Guides](#guides)\n  - [Understanding and Customizing Markup](https://github.com/joshwcomeau/react-collection-helpers/blob/master/documentation/markup.md)\n  - [Predicates in React Collection Helpers](https://github.com/joshwcomeau/react-collection-helpers/blob/master/documentation/predicates.md)\n  - [Comparators in React Collection Helpers](https://github.com/joshwcomeau/react-collection-helpers/blob/master/documentation/comparators.md)\n- [API Reference](#api-reference)\n  - [`\u003cEvery\u003e`](#every)\n  - [`\u003cFilter\u003e`](#filter)\n  - [`\u003cFind\u003e`](#find)\n  - [`\u003cFirst\u003e`](#first)\n  - [`\u003cLast\u003e`](#last)\n  - [`\u003cMap\u003e`](#map)\n  - [`\u003cReject\u003e`](#reject)\n  - [`\u003cReverse\u003e`](#reverse)\n  - [`\u003cSome\u003e`](#some)\n  - [`\u003cSort\u003e`](#sort)\n\n\n\n\n## Features\n\n- :sparkles: **Useful** - includes 10+ components to help you filter, sort, and slice collections.\n- :black_nib: **Designer-friendly** - make your designers' lives easier by writing components without complex inline logic.\n- :zap: **Tiny** - full build is only 2.5kb, and is modular so you can import only the components you need.\n- :muscle: **Performant** - [experiments show](https://github.com/joshwcomeau/react-collection-helpers/blob/master/tools/performance-checks.js) that these components are just as performant as native methods.\n- :wrench: **Customizable** - the wrapper element can be any element type you'd like (native _or_ composite), and all non-recognized props are passed through. Composing Collection Helpers does not create additional HTML markup!\n\n\n\n\n## Drawbacks\n\nSo, React Collection Helpers is an experiment, designed to test if React's component model makes sense when used for array manipulation.\n\nI believe that it's nicer, for the [reasons outlined above](#features), than doing vanilla JS manipulation within your component's render method. That said, *this is often the wrong place to be doing this kind of logic*.\n\nFor very large collections, or for components that re-render frequently, it makes sense to move this kind of intense manipulation into memoized functions. If you use Redux, then [reselect](https://github.com/reactjs/reselect) is likely a better place to do this kind of work.\n\nIt also means that your presentation layer never has to concern itself with this work, which is usually a good thing.\n\nFor small apps (or simple sections within large apps), React Collection Helpers can be a nice touch. For redux apps, though, there is often a better way.\n\nUltimately, React Collection Helpers is built as a starting point, not a final destination. I feel like with enough trial and error, we might stumble upon something genuinely innovative and useful. I'm going to continue experimenting, and I would encourage us all to keep an open mind, and an eye out for exciting new possibilities.\n\n\n\n\n## Installation\n\n```\nnpm i -S react-collection-helpers\n```\n\nUMD builds are also available via CDN:\n\n- [react-collection-helpers.js](https://unpkg.com/react-collection-helpers@1.1.0/umd/react-collection-helpers.js)\n- [react-collection-helpers.min.js](https://unpkg.com/react-collection-helpers@1.1.0/umd/react-collection-helpers.js)\n\n(If you use the UMD build, the global variable is `CollectionHelpers`)\n\n\n\n\n## Feedback Wanted\n\nThis project is an experiment to test the usefulness of collection manipulators in component form factor.\n\nWhen I say that it's an experiment, I don't necessarily mean that it's _experimental_. I'm pretty confident that it's stable and safe to use in production; the code is quite simple.\n\nRather, I mean that I'm not convinced that it solves a real problem. I'd like to hear from users who implement them; does it improve the development experience of you or your team? Do you think the idea has potential if it went in a certain direction? I'm open to exploring tangential ideas.\n\nLet me know [on Twitter](https://twitter.com/joshwcomeau), or [via email](mailto:joshwcomeau+rch@gmail.com)\n\n\n\n\n## Usage\n\nImport the component(s) you need:\n\n```jsx\n// ES6 modules\nimport { Find, Every, Map } from 'react-collection-helpers';\n\n// CommonJS\nconst { Find, Every, Map } = require('react-collection-helpers');\n```\n\nAlternatively, you can import components individually, to avoid bundling the components you don't use:\n\n```jsx\n// This method avoids bundling unused components, and reduces gzipped bundles\n// by about 1kb.\nimport Find from 'react-collection-helpers/lib/components/Find';\nimport Every from 'react-collection-helpers/lib/components/Every';\nimport Map from 'react-collection-helpers/lib/components/Map';\n```\n\n\n## Guides\n\nLearn more about how best to use React Collection Helpers with these in-depth guides:\n\n* [Understanding and Customizing Markup](https://github.com/joshwcomeau/react-collection-helpers/blob/master/documentation/markup.md)\n* [Predicates in React Collection Helpers](https://github.com/joshwcomeau/react-collection-helpers/blob/master/documentation/predicates.md)\n* [Comparators in React Collection Helpers](https://github.com/joshwcomeau/react-collection-helpers/blob/master/documentation/comparators.md)\n\n\n\n## API Reference\n\n### `\u003cEvery\u003e`\n\nRender the children if the predicate returns true for **every** child. A Fallback node can be provided, to be rendered if the predicate returns false for any child. Otherwise, nothing will be rendered.\n\nIf no predicate is provided, the content will be rendered as long as the collection has 1 item or more. If an empty collection is supplied, the fallback content will be rendered.\n\n#### Props\n\n| Prop         | Required | Types   | Notes    |\n|--------------|----------|---------|----------|\n| `collection` | ✓        | [`any`] | Can be implicitly passed by parent Collection Helpers\n| `predicate`  | ✕        | `function`/`object`| See [predicates](https://github.com/joshwcomeau/react-collection-helpers/tree/master/documentation/predicates.md) for more information |\n| `fallback`   | ✕        | `node` | Alternate content to be rendered if the predicate returns false on any items.\n\n#### Example\n\n```jsx\nconst collection = [\n  { id: 'a', src: '...', isLoaded: true },\n  { id: 'b', src: '...', isLoaded: true },\n  { id: 'c', src: '...', isLoaded: false },\n];\n\n\u003cEvery\n  collection={collection}\n  predicate={{ isLoaded: true }}\n  fallback={\u003cspan\u003eLoading...\u003c/span\u003e}\n\u003e\n  {item =\u003e \u003cimg key={item.id} src={item.src} /\u003e}\n\u003c/Every\u003e\n```\n\n\n### `\u003cFilter\u003e`\n\nRender only the children for which the predicate returns `true`.\n\n\n#### Props\n\n| Prop         | Required | Types   | Notes    |\n|--------------|----------|---------|----------|\n| `collection` | ✓        | [`any`] | Can be implicitly passed by parent Collection Helpers\n| `predicate`  | ✓        | `function`/`object`| See [predicates](https://github.com/joshwcomeau/react-collection-helpers/tree/master/documentation/predicates.md) for more information |\n\n#### Example\n\n```jsx\nconst collection = [\n  { id: 'a', name: 'apple', price: 1.00 },\n  { id: 'b', name: 'banana', price: 5.00 },\n  { id: 'c', name: 'carrot', price: 2.50 },\n];\n\n\u003cFilter collection={collection} predicate={item =\u003e (item.price \u003c 3)}\u003e\n  {item =\u003e \u003cdiv key={item.id}\u003e{item.name}\u003c/div\u003e}\n\u003c/Filter\u003e\n```\n\n\n### `\u003cFind\u003e`\n\nRender the first child for which the predicate returns `true`.\n\n\n#### Props\n\n| Prop         | Required | Types   | Notes    |\n|--------------|----------|---------|----------|\n| `collection` | ✓        | [`any`] | Can be implicitly passed by parent Collection Helpers\n| `predicate`  | ✓        | `function`/`object`| See [predicates](https://github.com/joshwcomeau/react-collection-helpers/tree/master/documentation/predicates.md) for more information |\n\n#### Example\n\n```jsx\nconst collection = [\n  { id: 'a', name: 'John', isAdmin: false },\n  { id: 'b', name: 'Jane', isAdmin: true },\n  { id: 'c', name: 'Jala', isAdmin: false },\n];\n\n\u003cFind collection={collection} predicate={{ isAdmin: true }}\u003e\n  {user =\u003e \u003cdiv key={user.id}\u003eYour group's admin is {user.name}\u003c/div\u003e}\n\u003c/Find\u003e\n```\n\n\n### `\u003cFirst\u003e`\n\nReturns the first 1 or more items of the collection. Generally only useful as a child to another Collection Helper.\n\n\n#### Props\n\n| Prop         | Required | Types   | Notes    |\n|--------------|----------|---------|----------|\n| `collection` | ✓        | [`any`] | Can be implicitly passed by parent Collection Helpers\n| `num`        | ✕        | `number`| Defaults to `1` |\n\n#### Example\n\n```jsx\nconst collection = [\n  { id: 'a', name: 'John', distance: 3.14 },\n  { id: 'b', name: 'Jane', distance: 0.45 },\n  { id: 'c', name: 'Jala', distance: 1.23 },\n];\n\n\u003cSort collection={collection} comparator=\"distance\"\u003e\n  \u003cFirst\u003e\n    {user =\u003e \u003cdiv key={user.id}\u003eYou are closest to {user.name}\u003c/div\u003e}\n  \u003c/First\u003e\n\u003c/Sort\u003e\n```\n\n\n### `\u003cLast\u003e`\n\nReturns the last 1 or more items of the collection. The opposite of `\u003cFirst\u003e`. Generally only useful as a child to another Collection Helper.\n\n\n#### Props\n\n| Prop         | Required | Types   | Notes    |\n|--------------|----------|---------|----------|\n| `collection` | ✓        | [`any`] | Can be implicitly passed by parent Collection Helpers\n| `num`        | ✕        | `number`| Defaults to `1` |\n\n#### Example\n\n```jsx\nconst collection = [\n  { id: 'a', name: 'John', distance: 3.14 },\n  { id: 'b', name: 'Jane', distance: 0.45 },\n  { id: 'c', name: 'Jala', distance: 1.23 },\n];\n\n\u003cSort collection={collection} comparator=\"distance\"\u003e\n  \u003cLast\u003e\n    {user =\u003e \u003cdiv key={user.id}\u003eYou are furthest from {user.name}\u003c/div\u003e}\n  \u003c/Last\u003e\n\u003c/Sort\u003e\n```\n\n\n### `\u003cMap\u003e`\n\nThe simplest Collection Helper, doesn't do very much. Can be useful to ensure consistency between your components.\n\n#### Props\n\n| Prop         | Required | Types   | Notes    |\n|--------------|----------|---------|----------|\n| `collection` | ✓        | [`any`] | Can be implicitly passed by parent Collection Helpers\n\n#### Example\n\n```jsx\nconst collection = [\n  { id: 'a', name: 'John' },\n  { id: 'b', name: 'Jane' },\n  { id: 'c', name: 'Jala' },\n];\n\n\u003cMap collection={collection}\u003e\n  {user =\u003e \u003cdiv key={user.id}\u003e{user.name}\u003c/div\u003e}\n\u003c/Map\u003e\n```\n\n\n### `\u003cReject\u003e`\n\nRender only the children for which the predicate returns `false`. The opposite of `\u003cFilter\u003e`.\n\n#### Props\n\n| Prop         | Required | Types   | Notes    |\n|--------------|----------|---------|----------|\n| `collection` | ✓        | [`any`] | Can be implicitly passed by parent Collection Helpers\n| `predicate`  | ✓        | `function`/`object`| See [predicates](https://github.com/joshwcomeau/react-collection-helpers/tree/master/documentation/predicates.md) for more information |\n\n#### Example\n\n```jsx\nconst collection = [\n  { id: 'a', name: 'apple', price: 1.00 },\n  { id: 'b', name: 'banana', price: 5.00 },\n  { id: 'c', name: 'carrot', price: 2.50 },\n];\n\n\u003cReject collection={collection} predicate={item =\u003e (item.price \u003e 3)}\u003e\n  {item =\u003e \u003cdiv key={item.id}\u003e{item.name}\u003c/div\u003e}\n\u003c/Reject\u003e\n```\n\n\n### `\u003cSome\u003e`\n\nRender the children if the predicate returns true for **any** child. A Fallback node can be provided, to be rendered if the predicate returns false for all children. Otherwise, nothing will be rendered.\n\nIf no predicate is provided, the content will be rendered as long as the collection has 1 item or more. If an empty collection is supplied, the fallback content will be rendered.\n\n#### Props\n\n| Prop         | Required | Types   | Notes    |\n|--------------|----------|---------|----------|\n| `collection` | ✓        | [`any`] | Can be implicitly passed by parent Collection Helpers\n| `predicate`  | ✕        | `function`/`object`| See [predicates](https://github.com/joshwcomeau/react-collection-helpers/tree/master/documentation/predicates.md) for more information |\n| `fallback`   | ✕        | `node` | Alternate content to be rendered if the predicate returns false on all items.\n\n#### Example\n\n```jsx\nconst collection = [\n  { id: 'a', username: 'sickskillz', hasWon: false },\n  { id: 'b', username: 'dabomb12345', hasWon: false },\n];\n\n\u003cSome\n  elementType={Leaderboard}\n  collection={collection}\n  predicate={{ hasWon: true }}\n\u003e\n  {user =\u003e \u003cLeaderboardRow key={user.id} {...user} /\u003e}\n\u003c/Some\u003e\n```\n\n\n### `\u003cSort\u003e`\n\nSorts the children based on a comparator.\n\n#### Props\n\n| Prop         | Required | Types   | Notes    |\n|--------------|----------|---------|----------|\n| `collection` | ✓        | [`any`] | Can be implicitly passed by parent Collection Helpers\n| `comparator` | ✓        | `function`/`object`| See [comparators](https://github.com/joshwcomeau/react-collection-helpers/tree/master/documentation/comparators.md) for more information |\n| `descending` | ✕        | `boolean` | Whether to sort in descending order, when providing a 'string' comparator. Defaults to `false` (string comparators sort in ascending).\n\n#### Example\n\n```jsx\nconst collection = [\n{ id: 'a', name: 'apple', price: 1.00 },\n{ id: 'b', name: 'banana', price: 5.00 },\n{ id: 'c', name: 'carrot', price: 2.50 },\n];\n\n\u003cSort collection={collection} comparator=\"price\"\u003e\n  {item =\u003e \u003cStoreItem key={item.id} {...item} /\u003e}\n\u003c/Sort\u003e\n```\n\n\n\n\n\n\n\u003c!-- Populate references above --\u003e\n[build-badge]: https://img.shields.io/travis/joshwcomeau/react-collection-helpers/master.png?style=flat-square\n[build]: https://travis-ci.org/joshwcomeau/react-collection-helpers\n\n[npm-badge]: https://img.shields.io/npm/v/react-collection-helpers.png?style=flat-square\n[npm]: https://www.npmjs.org/package/react-collection-helpers\n\n[coveralls-badge]: https://img.shields.io/coveralls/joshwcomeau/react-collection-helpers/master.png?style=flat-square\n[coveralls]: https://coveralls.io/github/joshwcomeau/react-collection-helpers\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshwcomeau%2Freact-collection-helpers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoshwcomeau%2Freact-collection-helpers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshwcomeau%2Freact-collection-helpers/lists"}