use-array-state (use-array-state)
Manages an array as a React state with built-in array manipulation methods.
v0.1.0
Usage
import { use-array-state } from "@/hooks"
1"use client";
2
3import React, { useState } from "react";
4
5import { Badge } from "@/components/ui/badge";
6import { Button } from "@/components/ui/button";
7import {
8 Card,
9 CardContent,
10 CardDescription,
11 CardFooter,
12 CardHeader,
13 CardTitle,
14} from "@/components/ui/card";
15import { Input } from "@/components/ui/input";
16
17import { useArrayState } from "@/components/hooks/use-array-state";
18
19export function UseArrayStateDemo() {
20 const [inputValue, setInputValue] = useState("");
21 const [updateIndex, setUpdateIndex] = useState("");
22 const [updateValue, setUpdateValue] = useState("");
23
24 const {
25 array,
26 length,
27 isEmpty,
28 first,
29 last,
30 push,
31 pop,
32 shift,
33 unshift,
34 insert,
35 remove,
36 update,
37 clear,
38 reset,
39 sort,
40 reverse,
41 filter,
42 } = useArrayState<string>({
43 initialValue: ["React", "TypeScript", "Next.js"],
44 onChange: (newArray) => {
45 console.log("Array changed:", newArray);
46 },
47 });
48
49 const handleAddItem = () => {
50 if (inputValue.trim()) {
51 push(inputValue.trim());
52 setInputValue("");
53 }
54 };
55
56 const handleUpdateItem = () => {
57 const index = parseInt(updateIndex);
58 if (!isNaN(index) && updateValue.trim()) {
59 update(index, updateValue.trim());
60 setUpdateIndex("");
61 setUpdateValue("");
62 }
63 };
64
65 const handleInsertAtStart = () => {
66 if (inputValue.trim()) {
67 unshift(inputValue.trim());
68 setInputValue("");
69 }
70 };
71
72 const handleRemoveItem = (index: number) => {
73 remove(index);
74 };
75
76 const handleFilterLongItems = () => {
77 filter((item) => item.length <= 6);
78 };
79
80 return (
81 <Card className="w-full max-w-2xl mx-auto">
82 <CardHeader>
83 <CardTitle>useArrayState</CardTitle>
84 <CardDescription>
85 A powerful hook for managing arrays as React state with built-in
86 manipulation methods.
87 </CardDescription>
88 </CardHeader>
89 <CardContent className="space-y-6">
90 {/* Array Display */}
91 <div>
92 <h3 className="text-sm font-medium mb-2">Current Array:</h3>
93 <div className="flex flex-wrap gap-2 min-h-[40px] p-3 border rounded-md bg-muted/20">
94 {array.map((item, index) => (
95 <Badge
96 key={index}
97 variant="secondary"
98 className="cursor-pointer hover:bg-destructive hover:text-destructive-foreground"
99 onClick={() => handleRemoveItem(index)}
100 >
101 {item} ×
102 </Badge>
103 ))}
104 {isEmpty && (
105 <span className="text-muted-foreground text-sm">
106 Array is empty
107 </span>
108 )}
109 </div>
110 </div>
111
112 {/* Array Stats */}
113 <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
114 <div className="text-center">
115 <div className="text-2xl font-bold">{length}</div>
116 <div className="text-xs text-muted-foreground">Length</div>
117 </div>
118 <div className="text-center">
119 <div className="text-sm font-medium truncate">{first || "N/A"}</div>
120 <div className="text-xs text-muted-foreground">First</div>
121 </div>
122 <div className="text-center">
123 <div className="text-sm font-medium truncate">{last || "N/A"}</div>
124 <div className="text-xs text-muted-foreground">Last</div>
125 </div>
126 <div className="text-center">
127 <div className="text-sm font-medium">{isEmpty ? "Yes" : "No"}</div>
128 <div className="text-xs text-muted-foreground">Empty</div>
129 </div>
130 </div>
131
132 <div className="border-t" />
133
134 {/* Add Items */}
135 <div className="space-y-3">
136 <h3 className="text-sm font-medium">Add Items:</h3>
137 <div className="flex gap-2">
138 <Input
139 placeholder="Enter item to add"
140 value={inputValue}
141 onChange={(e) => setInputValue(e.target.value)}
142 onKeyDown={(e) => {
143 if (e.key === "Enter") {
144 handleAddItem();
145 }
146 }}
147 />
148 <Button onClick={handleAddItem} disabled={!inputValue.trim()}>
149 Add to End
150 </Button>
151 <Button
152 onClick={handleInsertAtStart}
153 disabled={!inputValue.trim()}
154 variant="outline"
155 >
156 Add to Start
157 </Button>
158 </div>
159 </div>
160
161 {/* Update Item */}
162 <div className="space-y-3">
163 <h3 className="text-sm font-medium">Update Item:</h3>
164 <div className="flex gap-2">
165 <Input
166 placeholder="Index"
167 value={updateIndex}
168 onChange={(e) => setUpdateIndex(e.target.value)}
169 className="w-20"
170 />
171 <Input
172 placeholder="New value"
173 value={updateValue}
174 onChange={(e) => setUpdateValue(e.target.value)}
175 onKeyDown={(e) => {
176 if (e.key === "Enter") {
177 handleUpdateItem();
178 }
179 }}
180 />
181 <Button
182 onClick={handleUpdateItem}
183 disabled={!updateIndex.trim() || !updateValue.trim()}
184 variant="outline"
185 >
186 Update
187 </Button>
188 </div>
189 </div>
190
191 <div className="border-t" />
192
193 {/* Array Operations */}
194 <div className="space-y-3">
195 <h3 className="text-sm font-medium">Array Operations:</h3>
196 <div className="grid grid-cols-2 md:grid-cols-4 gap-2">
197 <Button
198 onClick={() => pop()}
199 disabled={isEmpty}
200 variant="outline"
201 size="sm"
202 >
203 Remove Last
204 </Button>
205 <Button
206 onClick={() => shift()}
207 disabled={isEmpty}
208 variant="outline"
209 size="sm"
210 >
211 Remove First
212 </Button>
213 <Button
214 onClick={() => sort()}
215 disabled={isEmpty}
216 variant="outline"
217 size="sm"
218 >
219 Sort A-Z
220 </Button>
221 <Button
222 onClick={() => reverse()}
223 disabled={isEmpty}
224 variant="outline"
225 size="sm"
226 >
227 Reverse
228 </Button>
229 <Button
230 onClick={handleFilterLongItems}
231 disabled={isEmpty}
232 variant="outline"
233 size="sm"
234 >
235 Filter Short
236 </Button>
237 <Button
238 onClick={clear}
239 disabled={isEmpty}
240 variant="destructive"
241 size="sm"
242 >
243 Clear All
244 </Button>
245 <Button onClick={reset} variant="outline" size="sm">
246 Reset
247 </Button>
248 </div>
249 </div>
250 </CardContent>
251 <CardFooter className="text-xs text-muted-foreground">
252 Click on items to remove them. Use the operations above to manipulate
253 the array.
254 </CardFooter>
255 </Card>
256 );
257}
258
Install
npx wkkkis-hooks add use-array-state
Options
Name | Type | Default | Description |
---|---|---|---|
— | UseArrayStateOptions | {} | Configuration options for the hook |
initialValue | T[] | [] | The initial array value |
onChange | (array: T[]) => void | null | Callback called whenever the array changes |
Type Safety
- The hook is fully type-safe with TypeScript generics.
- All methods maintain type information throughout operations.
- Prevents runtime errors with proper type checking.
Performance Optimization
- Uses useCallback to memoize all methods for optimal performance.
- Prevents unnecessary re-renders by checking for actual changes.
- Efficiently handles large arrays with immutable updates.
Change Detection
- The onChange callback is called whenever the array state changes.
- Changes are detected at the reference level for performance.
- Callbacks receive the new array as their argument.
SSR Compatibility
- Fully compatible with Server-Side Rendering.
- No browser-specific APIs used.
- Safe for use in Next.js and other SSR frameworks.
Files in this hook
Source | Destination |
---|---|
files/use-array-state.ts | src/hooks/use-array-state.ts |