fix: ESLint react-hooks 최신 규칙 호환
- useCallback → 일반 함수 + eslint-disable (초기 데이터 fetch) - ToastProvider: useCallback 프로퍼티 할당 → useMemo 객체 패턴 - SSAFYCallbackPage: eslint-disable-line 추가 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useAuth } from '../context/useAuth';
|
||||
import { getDownloadInfo } from '../api/download';
|
||||
@@ -14,15 +14,16 @@ export default function DownloadSection() {
|
||||
const { user } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const loadInfo = useCallback(() => {
|
||||
const loadInfo = () => {
|
||||
setReady(false);
|
||||
setLoadError(false);
|
||||
getDownloadInfo()
|
||||
.then((data) => { setInfo(data); setReady(true); })
|
||||
.catch(() => { setLoadError(true); setReady(true); });
|
||||
}, []);
|
||||
};
|
||||
|
||||
useEffect(() => { loadInfo(); }, [loadInfo]);
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect -- initial data fetch on mount
|
||||
useEffect(() => { loadInfo(); }, []);
|
||||
|
||||
const handlePlay = async () => {
|
||||
if (!user) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// TODO: Add tests for CRUD operations (load download info, upload launcher, upload game)
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { getDownloadInfo } from '../../api/download';
|
||||
import UploadForm from './UploadForm';
|
||||
import './AdminCommon.css';
|
||||
@@ -9,7 +9,7 @@ export default function DownloadAdmin() {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [loadError, setLoadError] = useState('');
|
||||
|
||||
const load = useCallback(() => {
|
||||
const load = () => {
|
||||
setLoading(true);
|
||||
setLoadError('');
|
||||
getDownloadInfo()
|
||||
@@ -22,9 +22,10 @@ export default function DownloadAdmin() {
|
||||
setLoadError('배포 정보를 불러올 수 없습니다.');
|
||||
})
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
};
|
||||
|
||||
useEffect(() => { load(); }, [load]);
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect -- initial data fetch on mount
|
||||
useEffect(() => { load(); }, []);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// TODO: Add tests for CRUD operations (list users, update role, delete user)
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { getUsers, updateUserRole, deleteUser } from '../../api/users';
|
||||
import { useAuth } from '../../context/useAuth';
|
||||
import { useToast } from '../toast/useToast';
|
||||
@@ -12,7 +12,7 @@ export default function UserAdmin() {
|
||||
const { user: me } = useAuth();
|
||||
const toast = useToast();
|
||||
|
||||
const load = useCallback(() => {
|
||||
const load = () => {
|
||||
setLoading(true);
|
||||
setFetchError(false);
|
||||
getUsers()
|
||||
@@ -22,8 +22,9 @@ export default function UserAdmin() {
|
||||
setFetchError(true);
|
||||
})
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
useEffect(() => { load(); }, [load]);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect -- initial data fetch on mount
|
||||
useEffect(() => { load(); }, []);
|
||||
|
||||
const handleRoleToggle = async (u) => {
|
||||
const newRole = u.role === 'admin' ? 'user' : 'admin';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useCallback, useRef } from 'react';
|
||||
import { useState, useCallback, useMemo, useRef } from 'react';
|
||||
import { ToastContext } from './toastContextValue';
|
||||
import './Toast.css';
|
||||
|
||||
@@ -20,17 +20,12 @@ export function ToastProvider({ children }) {
|
||||
return id;
|
||||
}, [removeToast]);
|
||||
|
||||
// Attaching methods to the toast function works because useCallback keeps
|
||||
// the reference stable across renders, so the .success/.error/.warn properties
|
||||
// persist. This is a pragmatic pattern — a plain object would be cleaner but
|
||||
// would change the public API consumed by useToast() callers.
|
||||
// IMPORTANT: This pattern relies on `addToast` being stable (no dependencies that change).
|
||||
// If addToast gains new dependencies, toast.success/error/warn will be stale on the old ref.
|
||||
// In that case, refactor to return an object { info, success, error, warn } from context.
|
||||
const toast = useCallback((message) => addToast(message, 'info'), [addToast]);
|
||||
toast.success = useCallback((message) => addToast(message, 'success'), [addToast]);
|
||||
toast.error = useCallback((message) => addToast(message, 'error'), [addToast]);
|
||||
toast.warn = useCallback((message) => addToast(message, 'warn'), [addToast]);
|
||||
const toast = useMemo(() => ({
|
||||
info: (message) => addToast(message, 'info'),
|
||||
success: (message) => addToast(message, 'success'),
|
||||
error: (message) => addToast(message, 'error'),
|
||||
warn: (message) => addToast(message, 'warn'),
|
||||
}), [addToast]);
|
||||
|
||||
return (
|
||||
<ToastContext.Provider value={toast}>
|
||||
|
||||
@@ -20,7 +20,7 @@ export default function SSAFYCallbackPage() {
|
||||
|
||||
const code = searchParams.get('code');
|
||||
if (!code) {
|
||||
setError('인가 코드가 없습니다.');
|
||||
setError('인가 코드가 없습니다.'); // eslint-disable-line react-hooks/set-state-in-effect -- error state from URL param check
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user