From f67cc9dac9e5dec5645b8974d0e8cfcff41be03d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=A0=95=ED=99=98/=EC=84=9C=EB=B9=84=EC=8A=A4?= =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=86=A0=ED=83=80=EC=9E=85=EA=B0=9C=EB=B0=9C?= =?UTF-8?q?=ED=8C=80?= Date: Sat, 28 Jun 2025 14:49:50 +0900 Subject: [PATCH] feat(utils): add renderTimes util --- src/index.ts | 1 + src/utils/renderTimes/index.ts | 1 + src/utils/renderTimes/renderTimes.spec.ts | 74 +++++++++++++++++++++++ src/utils/renderTimes/renderTimes.ts | 60 ++++++++++++++++++ 4 files changed, 136 insertions(+) create mode 100644 src/utils/renderTimes/index.ts create mode 100644 src/utils/renderTimes/renderTimes.spec.ts create mode 100644 src/utils/renderTimes/renderTimes.ts diff --git a/src/index.ts b/src/index.ts index 5a5911dc..2c236c09 100644 --- a/src/index.ts +++ b/src/index.ts @@ -28,3 +28,4 @@ export { useVisibilityEvent } from './hooks/useVisibilityEvent/index.ts'; export { buildContext } from './utils/buildContext/index.ts'; export { mergeProps } from './utils/mergeProps/index.ts'; export { mergeRefs } from './utils/mergeRefs/index.ts'; +export { renderTimes } from './utils/renderTimes/index.ts'; diff --git a/src/utils/renderTimes/index.ts b/src/utils/renderTimes/index.ts new file mode 100644 index 00000000..ae029cb2 --- /dev/null +++ b/src/utils/renderTimes/index.ts @@ -0,0 +1 @@ +export { renderTimes } from './renderTimes.ts'; diff --git a/src/utils/renderTimes/renderTimes.spec.ts b/src/utils/renderTimes/renderTimes.spec.ts new file mode 100644 index 00000000..3b25a3ed --- /dev/null +++ b/src/utils/renderTimes/renderTimes.spec.ts @@ -0,0 +1,74 @@ +import { describe, expect, it } from 'vitest'; + +import { renderTimes } from './renderTimes.ts'; + +describe('renderTimes', () => { + it('should render components the specified number of times', () => { + const result = renderTimes(3, index => `Item ${index}`); + + expect(result).toHaveLength(3); + expect(result).toEqual(['Item 0', 'Item 1', 'Item 2']); + }); + + it('should return empty array when count is 0', () => { + const result = renderTimes(0, index => `Item ${index}`); + + expect(result).toHaveLength(0); + expect(result).toEqual([]); + }); + + it('should handle negative count by returning empty array', () => { + const result = renderTimes(-1, index => `Item ${index}`); + + expect(result).toHaveLength(0); + expect(result).toEqual([]); + }); + + it('should call renderFunction with correct index for each iteration', () => { + const indices: number[] = []; + renderTimes(4, index => { + indices.push(index); + return index; + }); + + expect(indices).toEqual([0, 1, 2, 3]); + }); + + it('should work with React components', () => { + const result = renderTimes(2, index => ({ + type: 'div', + key: index.toString(), + props: { children: `Component ${index}` }, + })); + + expect(result).toHaveLength(2); + expect(result[0]).toEqual({ + type: 'div', + key: '0', + props: { + children: 'Component 0', + }, + }); + expect(result[1]).toEqual({ + type: 'div', + key: '1', + props: { + children: 'Component 1', + }, + }); + }); + + it('should work with different return types', () => { + const numberResult = renderTimes(3, index => index * 2); + + expect(numberResult).toEqual([0, 2, 4]); + + const booleanResult = renderTimes(2, index => index % 2 === 0); + + expect(booleanResult).toEqual([true, false]); + + const nullResult = renderTimes(2, () => null); + + expect(nullResult).toEqual([null, null]); + }); +}); diff --git a/src/utils/renderTimes/renderTimes.ts b/src/utils/renderTimes/renderTimes.ts new file mode 100644 index 00000000..d3db8509 --- /dev/null +++ b/src/utils/renderTimes/renderTimes.ts @@ -0,0 +1,60 @@ +import type { ReactNode } from 'react'; + +/** + * @description + * `renderTimes` is a utility function that renders components a specified number of times. + * It's useful for creating repeated UI elements like lists, grids, skeleton loaders, or pagination items + * without manual duplication or verbose Array.from constructs. + * + * @param {number} count - The number of times to render the component. Returns empty array if count is 0 or negative. + * @param {(index: number) => ReactNode} renderFunction - Function that receives the current index (0-based) and returns a ReactNode to render. + * + * @returns {ReactNode[]} An array of ReactNode elements. + * + * @example + * // Basic list rendering + * function ItemList() { + * return ( + *
+ * {renderTimes(5, (index) => ( + *
Item {index + 1}
+ * ))} + *
+ * ); + * } + * + * @example + * // Skeleton loading state + * function ProductSkeleton() { + * return ( + *
+ * {renderTimes(8, (index) => ( + *
+ *
+ *
+ *
+ *
+ * ))} + *
+ * ); + * } + * + * @example + * // Pagination dots + * function PaginationDots({ totalSlides, currentSlide }) { + * return ( + *
+ * {renderTimes(totalSlides, (index) => ( + *
+ * ); + * } + */ +export function renderTimes(count: number, renderFunction: (index: number) => ReactNode): ReactNode[] { + return Array.from({ length: count }, (_, index) => renderFunction(index)); +}