Skip to content

Commit 608a852

Browse files
Merge pull request #5 from Ashish-simpleCoder/develop
New docs changes and minor refactoring of components [chore]: enable caching for prettier format script in package.json [docs]: update readme doc [refactor]: add prop type validation in For component [test]: add re-render and error handling test case for For component [perf]: create fixed size array and remove useless type conversion fo… [refactor]: update the type definition for data prop in For component [refactor]: update logic for rendering the child of switch component … [chore]: update vitest config for file exntesion to include in test
2 parents 478eed3 + 434022c commit 608a852

8 files changed

Lines changed: 208 additions & 72 deletions

File tree

.changeset/old-crabs-applaud.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'classic-react-components': minor
3+
---
4+
5+
- [docs]: update examples and add more descrition of the components
6+
- [refactor]: use normal for loop to iterate over array in Switch component instead of Children.map function

README.md

Lines changed: 135 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
# 🚀 classic-react-components
22

3-
- A Simple React Library of `Utility Components`.
4-
- Write jsx in `maintainable` and `readable` way, and fun too.
3+
## Intro
4+
5+
- Simplifying the way you write conditional and loops in JSX.
6+
7+
- Adding `If-Else` like syntax for conditional jsx.
8+
- Adding `For` component to map over the data within jsx.
9+
- Adding `Switch-Case` to your jsx.
510

611

712
<br />
@@ -20,10 +25,11 @@
2025

2126
## Features
2227

23-
- Comes with treeshaking
24-
- Typescript support
28+
- Built in Typescript
29+
- Supports Treeshaking
2530
- Small bundle size
2631
- Minimal and Easy to use
32+
- Open Source
2733

2834
## Installation
2935

@@ -38,6 +44,11 @@ For pnpm users
3844
```bash
3945
$ pnpm install classic-react-components
4046
```
47+
For bun users
48+
49+
```bash
50+
$ bun install classic-react-components
51+
```
4152

4253
For yarn users
4354

@@ -53,30 +64,27 @@ $ yarn add classic-react-components
5364
- [For](#for)
5465
- [Switch](#switch)
5566

56-
### If
67+
## If
5768

5869
| Prop | Type | Required | Default Value | Description |
5970
| --------- | :-------: | :------: | :-----------: | -------------------------------------------------------------------------------------------- |
60-
| condition | any || false | Based on evaluation of the condition flag the component will return null or children |
61-
| children | ReactNode || null | To render the children |
62-
| suspense | boolean || false | Needed to show fallback until its children have finished loading |
63-
| fallback | ReactNode || null | Fallback needed to show until the component is loaded fully. Needed for suspensed components |
71+
| condition | any || false | Based on the evaluation of `condition` prop, either children or null will be rendered |
72+
| children | ReactNode || null | Renders the passed children |
73+
| suspense | boolean || false | Used for rendering lazily loaded components |
74+
| fallback | ReactNode || null | Used for showing the fallback until the suspensed children have been loaded. |
6475

6576
### Working
6677

67-
- Based on the condition the children are rendered.
68-
- If the condition is true then the childeren will render otherwise it will return null.
69-
70-
- For one children
71-
72-
- If condition is true then children will be rendered.
73-
- If condition is false then null gets returned.
78+
- Based on evaulation of the condition flag the children are rendered.
79+
- If the condition is true then it will render the children otherwise null.
80+
- Working with one child
81+
- If condition is true then child will be rendered.
82+
- If condition is false then null gets rendered.
83+
- Working with children(more than one child)
84+
- If condition is true then the first child will be rendered.
85+
- Otherwise the all of the children will be rendered excluding the first child.
7486

75-
- For multiple children
76-
- If conndition is true then the first children will rendered.
77-
- Otherwise the all of the children will be rendered excluding the first children.
78-
79-
### Example
87+
### Examples
8088

8189
```tsx
8290
import { If } from 'classic-react-components'
@@ -106,7 +114,7 @@ export default function YourComponent() {
106114
}
107115
```
108116

109-
### Usage with Suspense
117+
#### <i>Usage with Suspense</i>
110118

111119
```tsx
112120
import { If, Then, Else } from 'classic-react-components'
@@ -133,7 +141,35 @@ export default function YourComponent() {
133141
}
134142
```
135143

136-
### Then
144+
145+
### Replacing ternary and short-circuit
146+
147+
```tsx
148+
const show = true // some state, which will be toggled to true|false
149+
150+
// ❌ ternary operator
151+
{ show ? <h1>main content</h1>:<h1>fallback</h1> }
152+
// ❌ short circuit
153+
{ show && <h1>main content</h1> }
154+
155+
156+
// ✅ replace ternary
157+
<If>
158+
<Then>
159+
<h1>main content</h1>
160+
</Then>
161+
<Else>
162+
<h1>fallback</h1>
163+
</Else>
164+
</If>
165+
166+
// ✅ replace short circuit
167+
<If>
168+
<h1>main content</h1>
169+
</If>
170+
```
171+
172+
## Then
137173

138174
| Prop | Type | Required | Default Value | Description |
139175
| -------- | :-------: | :------: | :-----------: | --------------------------- |
@@ -144,7 +180,7 @@ export default function YourComponent() {
144180
- It should be used in-conjunction with `If` commponent.
145181
- It renders the passed children.
146182

147-
### Example
183+
### Examples
148184

149185
```tsx
150186
import { If, Then } from 'classic-react-components'
@@ -162,7 +198,7 @@ export default function YourComponent() {
162198
}
163199
```
164200

165-
### Else
201+
## Else
166202

167203
| Prop | Type | Required | Default Value | Description |
168204
| -------- | :-------: | :------: | :-----------: | --------------------------- |
@@ -173,7 +209,7 @@ export default function YourComponent() {
173209
- It should be used in-conjunction with `If` commponent.
174210
- It renders the passed children.
175211

176-
### Example
212+
### Examples
177213

178214
```tsx
179215
import { If, Then, Else } from 'classic-react-components'
@@ -194,19 +230,20 @@ export default function YourComponent() {
194230
}
195231
```
196232

197-
### For
233+
## For
198234

199235
| Prop | Type | Required | Default Value | Description |
200236
| -------- | :-------: | :------: | :-----------: | ---------------------------------------------- |
201-
| data | Array || undefined | Needed for mapping |
237+
| data | Array || undefined | Used for looping over the data and rendering the children |
202238
| children | ReactNode || null | Renders the `JSX` returned from child function |
203239

204240
### Working
205241

206-
- Replacement for Array.map().
242+
- Replacement of `Array.map` method used for rendering the list in jsx.
207243
- Used to iterate over an array of items and renders the `JSX` based on the provided child function.
208244

209-
### Example
245+
246+
### Examples
210247

211248
```tsx
212249
import { For } from 'classic-react-components'
@@ -229,21 +266,41 @@ export default function YourComponent() {
229266
}
230267
```
231268

232-
### Switch
269+
### Replacing Array.map used in jsx for rendering the list
270+
271+
```tsx
272+
const data = [1,2,3] // some async data
273+
274+
// ❌ using Array.map to render jsx
275+
{data.length > 0 && data.map((item, index) => {
276+
return <CardComponent key={item.id}>{item.course}</CardComponent>
277+
})}
278+
279+
280+
// ✅ using For component to render jsx without needing to check if data is defined or not
281+
<For data={data}>
282+
{(item, index) => {
283+
return <CardComponent key={item.id}>{item.course}</CardComponent>
284+
}}
285+
</For>
286+
```
287+
288+
289+
## Switch
233290

234291
| Prop | Type | Required | Default Value | Description |
235292
| -------- | :-------: | :------: | :-----------: | ---------------------------------------------------------------- |
236-
| item | any || undefined | The value of Switch |
237-
| children | ReactNode || - | Renders the children of matched case if found, else default case |
293+
| item | any || undefined | The value used for comparing with all of the cases |
294+
| children | ReactNode || - | Used for rendering the children of matched case if found, else Default Case's children will be rendered |
238295

239296
### Working
240297

241298
- Renders the children of particular matched case for given prop `item(switch value)`.
242-
- If no case matches for given prop `item`, the `Default` case will be rendered.
299+
- If none of cases are matched for given prop `item`, the `Default` case will be rendered.
243300

244301
> **Note:** The order of Default Case does not matter.
245302
246-
### Example
303+
### Examples
247304

248305
```tsx
249306
import { Switch } from 'classic-react-components'
@@ -272,4 +329,47 @@ export default function YourComponent({ item }: { item: 'coding' | 'sleep' }) {
272329
</div>
273330
)
274331
}
332+
333+
```
334+
### Replacing object switching for rendering the jsx
335+
```tsx
336+
const item: "sleep"|"coding" = "sleep"
337+
338+
// ❌ using old object switching
339+
// first define seperate object and match the case manually and can not define fallback case here at all
340+
const itemSwitches = {
341+
"coding":<div>coing-case</div>,
342+
"sleep":<div>sleep-case</div>,
343+
}
344+
const MatchedCase = itemSwitches(item) ?? <div>fallback</div> // manually giving fallback
345+
346+
// render in the jsx
347+
{MatchedCase}
348+
349+
350+
351+
// ✅ using Switch component
352+
353+
// much better, we do not have to lookup for the switch logic and jumping between states and jsx unlike with Object switching
354+
355+
// it support default case if no case is matched. we can not do it in one plase with object switching
356+
357+
// it is typesafe
358+
<Switch item={item}>
359+
{({ Case, Default }) => {
360+
return (
361+
<>
362+
<Case value='coding'>
363+
<div>coing-case</div>
364+
</Case>
365+
<Case value='sleep'>
366+
<div>sleep-case</div>
367+
</Case>
368+
<Default>
369+
<div>this is default case</div>
370+
</Default>
371+
</>
372+
)
373+
}}
374+
</Switch>
275375
```

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"type-check": "tsc",
3434
"size": "size-limit",
3535
"cs": "pnpm changeset",
36-
"format-code": "prettier --write ./src",
36+
"format-code": "prettier --write ./src --cache",
3737
"test": "vitest --coverage"
3838
},
3939
"peerDependencies": {

src/lib/components/For/For.test.tsx

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,56 @@ describe('For.tsx', () => {
1616
render(<For></For>)
1717
})
1818

19-
it('should throw error if children is not function', () => {
19+
it('should throw error if data is not type of an array', () => {
20+
let data = {}
21+
22+
// prettier-ignore
23+
// @ts-expect-error
24+
expect(() =>render(<For data={data}><div data-testid='child'></div></For>)).toThrowError('Type of data prop must be an array, but got object type.')
25+
26+
data = 'sdfsdfs'
27+
// prettier-ignore
28+
// @ts-expect-error
29+
expect(() =>render(<For data={data}><div data-testid='child'></div></For>)).toThrowError('Type of data prop must be an array, but got string type.')
30+
31+
data = () => {}
32+
// prettier-ignore
33+
// @ts-expect-error
34+
expect(() =>render(<For data={data}><div data-testid='child'></div></For>)).toThrowError('Type of data prop must be an array, but got function type.')
35+
36+
expect(screen.queryByTestId('child')).not.toBeInTheDocument()
37+
})
38+
39+
it('should throw error if children is not type of function', () => {
2040
const data = [{ name: 'react' }, { name: 'nextjs' }, { name: 'typescript' }]
2141

2242
// prettier-ignore
2343
// @ts-expect-error
24-
expect(() =>render(<For data={data}><div data-testid='child'></div></For>)).toThrowError('Children type must be a function.')
44+
expect(() =>render(<For data={data}><div data-testid='child'></div></For>)).toThrowError('Type of children prop must be a function but got object type.')
2545

2646
expect(screen.queryByTestId('child')).not.toBeInTheDocument()
2747
})
2848

2949
it('should render all of the children', () => {
30-
const data = [{ name: 'react' }, { name: 'nextjs' }, { name: 'typescript' }]
50+
let data = [{ name: 'react' }, { name: 'nextjs' }, { name: 'typescript' }]
51+
52+
const { rerender } = render(
53+
<For data={data}>
54+
{(item, i) => (
55+
<div key={i} data-testid={item.name}>
56+
{item.name}
57+
</div>
58+
)}
59+
</For>
60+
)
61+
expect(screen.queryByTestId('react')).toBeInTheDocument()
62+
expect(screen.queryByTestId('nextjs')).toBeInTheDocument()
63+
expect(screen.queryByTestId('typescript')).toBeInTheDocument()
64+
65+
// re-render with new data
66+
data = [{ name: 'react' }, { name: 'nextjs' }, { name: 'vuejs' }, { name: 'typescript' }]
3167

32-
render(
68+
rerender(
3369
<For data={data}>
3470
{(item, i) => (
3571
<div key={i} data-testid={item.name}>
@@ -40,6 +76,7 @@ describe('For.tsx', () => {
4076
)
4177
expect(screen.queryByTestId('react')).toBeInTheDocument()
4278
expect(screen.queryByTestId('nextjs')).toBeInTheDocument()
79+
expect(screen.queryByTestId('vuejs')).toBeInTheDocument()
4380
expect(screen.queryByTestId('typescript')).toBeInTheDocument()
4481
})
4582
})

src/lib/components/For/For.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import React from 'react'
2626
)
2727
}
2828
*/
29-
export default function For<T extends any[]>({
29+
export default function For<T extends readonly any[]>({
3030
data,
3131
children = null,
3232
}: {
@@ -35,14 +35,17 @@ export default function For<T extends any[]>({
3535
}) {
3636
if (!data || children === null) return <></>
3737

38+
if (!Array.isArray(data)) {
39+
throw new Error(`Type of data prop must be an array, but got ${typeof data} type.`)
40+
}
41+
3842
if (typeof children != 'function') {
39-
throw new Error('Children type must be a function.')
43+
throw new Error(`Type of children prop must be a function but got ${typeof children} type.`)
4044
}
4145

42-
let arr: JSX.Element[] = []
43-
for (let i = 0; i < Number(data.length); i++) {
44-
const element = children(data[i], i)
45-
arr.push(element)
46+
const arr: JSX.Element[] = new Array(data.length)
47+
for (let i = 0; i < data.length; i++) {
48+
arr.push(children(data[i], i))
4649
}
4750

4851
return <>{arr}</>

0 commit comments

Comments
 (0)