https://github.com/coxcore/react-loop-item
A simple component that repeatedly creates components.
https://github.com/coxcore/react-loop-item
Last synced: about 2 months ago
JSON representation
A simple component that repeatedly creates components.
- Host: GitHub
- URL: https://github.com/coxcore/react-loop-item
- Owner: coxcore
- License: mit
- Created: 2020-11-21T10:15:57.000Z (over 5 years ago)
- Default Branch: main
- Last Pushed: 2022-12-01T16:18:55.000Z (over 3 years ago)
- Last Synced: 2025-10-20T00:43:18.381Z (8 months ago)
- Language: JavaScript
- Homepage:
- Size: 277 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# react-loop-item
> A simple component that repeatedly creates components.
[](https://www.npmjs.com/package/react-loop-item) [](https://standardjs.com)
## Install
```bash
npm install react-loop-item --save
```
or
```bash
yarn add react-loop-item
```
## Usage
### ``
```jsx
import { LoopItem } from "react-loop-item";
const Articles = () => {
// [list]: props
const itemProps = [
{ contents: "1. Article sample A" },
{ contents: "2. Article sample B" },
];
return ;
};
// [target]: Item component of list
const Item = ({ contents }) =>
{contents}
;
```
### ``
> `[version] ^1.1.0`
```jsx
import { ListWrap } from "react-loop-item";
const Articles = () => {
// [list]: props
const itemProps = [
{ contents: "1. Article sample A" },
{ contents: "2. Article sample B" },
];
return (
props
target={Item}
list={itemProps}
/>
);
};
// [target]: Item component of list
const Item = ({ contents }) =>
```
### `loop()`
```jsx
import { LoopItem, loop } from "react-loop-item";
loop(Item, list, each, instead, hidden, memo);
// or
;
```
## Props
### target (required)
> `[type] elementType(React.Component, React.FC, React.forwardRef, string)`
Component to be created repeatedly.
```jsx
// Component
;
// Tag name
;
```
### list (optional)
> `[type] Array | number`
Item data array or number of items.
```jsx
// Array
;
// Count
;
```
### each (optional)
> `[type] Function`
Callback function that converts each element of `list` to props for `target` when rendering `target` component.
If `each` is omitted, `list` element is used as it is.
> `each` has two arguments. (element and index of `list`)
```jsx
// [list]: Raw datas
const model = [{ foo: "bar" }, { foo: "bar" }];
// [each]: Formatter for props
const getProps = (data, index) => ({
// Properties
value: data.foo,
// Callbacks
onClick: (event) => {
event.preventDefault();
console.log(model, data, index);
},
});
// [target]: has value and onClick
const Anchor = ({ value, onClick }) => (
{value}
);
;
```
### tag (optional)
> `[type] string`, `[version] ^1.1.0`, `[for] ListWrap`
Set tag name of parent element to wrap items.
```jsx
/>
// or
```
### instead (optional)
> [type] React.ReactNode
Element to return instead of null when `list` is empty. Use strings or element, no component.
> target={Component} instead={strings or element}
```jsx
// [list] : No data
const model = [];
// [instead]: Element to render instead of blank
const noData = no data;
// Do not use component
// const noData = () => no data;
;
```
### hidden (optional)
> `[type] boolean`
Prevent rendering.
```jsx
// or
```
### memo (optional)
> `[type] string | boolean`, `[version] ^1.1.2`
Whether to cache `target` using `React.memo`.
To use this feature, enter prop name of `target` you want to use as `key` in list, or `true`.
Use it when absolutely necessary. Frequent use of `React.memo` is not recommended.
```jsx
// or
```
## Examples
### AnchorList.jsx
```jsx
import React from "react";
import { ListWrap } from "react-loop-item";
import style from "./AnchorList.module.css";
// needs raw data array and props formatter.
const AnchorList = ({ list, each }) => (
);
// Check target props
const Item = ({ label, href, onClick }) => (
{label}
);
// What to display instead of the
-
{label}
-
{description}({visited})
const noData =
export default AnchorList;
```
### Tags.jsx
```jsx
import React from "react";
import { LoopItem } from "react-loop-item";
import style from "./Tags.module.css";
// If you already know about raw datas,
// define props formatter in this component.
const Tags = ({ list }) => (
);
const Item = ({ value }) => (
{value}
);
// Convert string to props
const getProps = (text, index) => ({
value: text,
});
export default Tags;
```
### ListContainer.jsx
```jsx
import React from "react";
import AnchorList from "./AnchorList";
import Tags from "./Tags";
const ListContainer = () => {
// raw datas
const siteList = [
{ url: "aaa.com", description: "aaa site", visited: 4 },
{ url: "bbb.com", description: "bbb site", visited: 2 },
{ url: "ccc.com", description: "ccc site", visited: 8 },
];
// Formatter for props of
const getProps = (data, index) => {
// raw datas (element and index of siteList)
const { url, description, visited } = data;
// Props
return {
key: url, // If key is omitted, index is used
label: description,
href: url,
onClick(event) {
event.preventDefault();
console.log(siteList, index, visited);
},
};
};
// raw datas
const tagList = ["react", "loop", "for", "each", "list"];
return (
{/* Your components */}
);
};
export default ListContainer;
```
## Tips
### Injecting Callbacks
If the structure of the raw data is fixed, the component using `LoopItem` defines props a formatter for the list item component.
Then use the parent component's state or props to develop functions to use as callback.
```jsx
import React from "react";
import AnchorList from "./AnchorList";
const ListContainer = () => {
// Code to manage model
// ...
const updateVisited = (url, count) => {
// Do something for updating model
};
// Callbacks injector for of
const getItemCallbacks = (data, index) => {
const { url, description, visited } = data;
// Callbacks
return {
onClick(event) {
event.preventDefault();
// Update visited
updateVisited(url, visited + 1);
},
};
};
return (
{/* Your component */}
);
};
export default ListContainer;
```
```jsx
import React from "react";
import { LoopItem } from "react-loop-item";
import style from "./AnchorList.module.css";
// needs raw datas and callbacks injector.
const AnchorList = ({ list, each }) => {
// Formatter for props
const getItemProps = (data, index) => {
const { url, description, visited } = data;
return {
// Properties
key: url,
href: url,
label: description,
// Inject callbacks
...each(data, index),
};
};
return (
);
};
// Check target props
const Item = ({ label, href, onClick }) => (
);
export default AnchorList;
```
### Rendering Optimization
If rendering optimization is required, set the `memo` option.
For this to work smoothly, you need to manage the elements of the `list` as immutable objects. And make sure the references to the `each` callback don't change.
```jsx
import React, { useReducer, useCallback } from "react";
import { ListWrap } from "react-loop-item";
// Demo data
const siteList = [
{ url: "aaa.com", description: "aaa site", visited: 4 },
{ url: "bbb.com", description: "bbb site", visited: 2 },
{ url: "ccc.com", description: "ccc site", visited: 8 },
];
// List reducer
const reducer = (state, url) =>
state.map((item) =>
// Returns new object only if it is a target.
item.url !== url
? item
: {
...item,
visited: item.visited + 1,
}
);
const MemoList = () => {
// Visit is dispatch
const [list, visit] = useReducer(reducer, siteList);
// Cached each
const each = useCallback(
(data, index) => ({
...data,
onClick(event) {
event.preventDefault();
visit(data.url);
},
}),
[visit] // Visit does not change the reference
);
// Try changing memo
return (
);
};
const Anchor = ({ url, description, visited, onClick }) => {
// Check rendering
console.log("rendering!", url);
return (
);
};
export default MemoList;
```
## License
MIT © [coxcore](https://github.com/coxcore)