React/Next.js component design, hooks, state management, performance optimization, and accessibility best practices for frontend development.
React/Next.jsコンポーネント設計、hooks、状態管理の専門知識。
interface ButtonProps {
label: string;
onClick: () => void;
variant?: 'primary' | 'secondary';
disabled?: boolean;
}
export const Button: React.FC<ButtonProps> = ({
label,
onClick,
variant = 'primary',
disabled = false
}) => {
return (
<button
className={`btn btn-${variant}`}
onClick={onClick}
disabled={disabled}
>
{label}
</button>
);
};
const [count, setCount] = useState(0);
useEffect(() => {
// 副作用(API呼び出し、購読など)
fetchData();
return () => {
// クリーンアップ
};
}, [dependency]); // 依存配列
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b], // 依存配列
);
const expensiveValue = useMemo(
() => computeExpensiveValue(a, b),
[a, b]
);
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(data => {
setData(data);
setLoading(false);
})
.catch(err => {
setError(err);
setLoading(false);
});
}, [url]);
return { data, loading, error };
}
import { useQuery } from '@tanstack/react-query';
function Users() {
const { data, isLoading, error } = useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then(res => res.json())
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <ul>{data.map(user => <li key={user.id}>{user.name}</li>)}</ul>;
}
<button>, <nav>, <main>など