🎉 init: 小龙的工作空间
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
|
||||
// Generic data type for auth
|
||||
type Auth = Record<string, unknown>;
|
||||
|
||||
/**
|
||||
* Fetch and manage auth data.
|
||||
*/
|
||||
export function useAuth() {
|
||||
const [data, setData] = useState<Auth[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
const res = await fetch(`/api/auth`);
|
||||
const json = await res.json();
|
||||
setData(Array.isArray(json) ? json : json?.data || []);
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : "Failed to load data");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [fetchData]);
|
||||
|
||||
return { data, loading, error, refetch: fetchData };
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
export function useDebounce<T>(value: T, delay: number = 300): T {
|
||||
const [debounced, setDebounced] = useState(value);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => setDebounced(value), delay);
|
||||
return () => clearTimeout(timer);
|
||||
}, [value, delay]);
|
||||
|
||||
return debounced;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useCallback } from "react";
|
||||
|
||||
interface UseFormOptions<T> {
|
||||
initialValues: T;
|
||||
onSubmit: (values: T) => Promise<void>;
|
||||
}
|
||||
|
||||
export function useForm<T extends Record<string, unknown>>({ initialValues, onSubmit }: UseFormOptions<T>) {
|
||||
const [values, setValues] = useState<T>(initialValues);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const setField = useCallback(<K extends keyof T>(field: K, value: T[K]) => {
|
||||
setValues(prev => ({ ...prev, [field]: value }));
|
||||
}, []);
|
||||
|
||||
const handleSubmit = useCallback(async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
setSubmitting(true);
|
||||
setError(null);
|
||||
await onSubmit(values);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : "Submit failed");
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
}, [values, onSubmit]);
|
||||
|
||||
return { values, setField, submitting, error, handleSubmit };
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
|
||||
// Generic data type for 阅读进度
|
||||
type Item = Record<string, unknown>;
|
||||
|
||||
/**
|
||||
* Fetch and manage 阅读进度 data.
|
||||
*/
|
||||
export function useItem() {
|
||||
const [data, setData] = useState<Item[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
const res = await fetch(`/api/阅读进度`);
|
||||
const json = await res.json();
|
||||
setData(Array.isArray(json) ? json : json?.data || []);
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : "Failed to load data");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [fetchData]);
|
||||
|
||||
return { data, loading, error, refetch: fetchData };
|
||||
}
|
||||
Reference in New Issue
Block a user