개발 공부

Next.js, TypeScript, ESLint를 사용할 때 유의할 점 본문

웹개발 (자바, 스프링, React)/Next.js

Next.js, TypeScript, ESLint를 사용할 때 유의할 점

아이셩짱셩 2024. 11. 13. 11:52

1. Link 컴포넌트 사용하기 (Next.js)

Next.js에서는 페이지 간 내비게이션을 위해 HTML의 <a> 태그 대신 next/link <Link> 컴포넌트를 사용하는 것이 필수입니다. 이를 통해 클라이언트 사이드 내비게이션이 가능해지며, 페이지 전환이 더 빠르고 효율적입니다.

import React from 'react';

// 부적절한 코드
const Header: React.FC = () => {
    return (
        <header>
            <h1>My Admin App</h1>
            <nav>
                <ul>
                    <li><a href="/">홈</a></li> {/* HTML a 태그 사용 */}
                </ul>
            </nav>
        </header>
    );
};

// 적절한 코드
const HeaderWithLink: React.FC = () => {
    return (
        <header>
            <h1>My Admin App</h1>
            <nav>
                <ul>
                    <li><Link href="/">홈</Link></li> {/* Link 컴포넌트 사용 */}
                </ul>
            </nav>
        </header>
    );
};

 

2. 상태 업데이트 함수 사용하기 (React)

React의 useState 훅을 사용하여 상태를 정의한 경우, 해당 상태를 업데이트하는 함수(예: setDashboardData)가 사용되지 않으면 ESLint 경고가 발생합니다. 상태를 업데이트하는 로직을 반드시 포함해야 합니다

// 부적절한 코드
const DashboardPage: React.FC = () => {
    const [dashboardData, setDashboardData] = useState(null); // 상태 정의

    useEffect(() => {
        const fetchDashboardData = async () => {
            const data = await fetch('/api/dashboard');
            // setDashboardData(data); // 상태 업데이트 함수 미사용
        };

        fetchDashboardData();
    }, []);
    
    return <div>대시보드</div>;
};

// 적절한 코드
const DashboardPageWithFetch: React.FC = () => {
    const [dashboardData, setDashboardData] = useState(null);

    useEffect(() => {
        const fetchDashboardData = async () => {
            const response = await fetch('/api/dashboard');
            const data = await response.json();
            setDashboardData(data); // 상태 업데이트 함수 사용
        };

        fetchDashboardData();
    }, []);
    
    return <div>{dashboardData ? '데이터 로드 완료' : '로딩 중...'}</div>;
};

 

3. 타입 안전성 유지하기 (TypeScript)

TypeScript를 사용할 때는 가능한 한 구체적인 타입을 지정해야 합니다. 예를 들어, any 대신 unknown이나 구체적인 인터페이스를 사용하는 것이 좋습니다. 이는 코드의 안정성을 높이고 잠재적인 오류를 줄이는 데 도움이 됩니다.

// 부적절한 코드
const fetchData = async (): Promise<any> => { // any 타입 사용
    const response = await fetch('/api/data');
    return response.json();
};

// 적절한 코드
interface MyDataType {
    id: number;
    name: string;
}

const fetchDataWithType = async (): Promise<MyDataType> => { // 구체적인 타입 사용
    const response = await fetch('/api/data');
    return response.json();
};

 

4. Error Handling (Next.js)

Next.js에서 오류 처리는 매우 중요합니다. error.js 파일을 사용하여 특정 라우트에서 발생하는 오류를 처리할 수 있습니다. 이 파일은 해당 라우트와 그 하위 컴포넌트에서 발생하는 오류를 잡아내고 사용자에게 적절한 UI를 제공하는 역할을 합니다.

 
// 부적절한 코드
const fetchDashboardData = async () => {
    const response = await fetch('/api/dashboard');
    if (!response.ok) {
        console.error('Error fetching data'); // 단순 로그 출력
    }
};

// 적절한 코드
const fetchDashboardDataWithErrorHandling = async () => {
    try {
        const response = await fetch('/api/dashboard');
        if (!response.ok) throw new Error('Failed to fetch data');
        const data = await response.json();
        // 데이터 처리 로직...
    } catch (error) {
        console.error('Error fetching dashboard data:', error);
        // 사용자에게 오류 메시지 표시 로직 추가 가능
    }
};

 

5. 전역 에러 처리 (Next.js)

루트 레이아웃에서 발생하는 오류는 global-error.js 파일을 통해 처리할 수 있습니다. 이 파일은 애플리케이션 전체에 대한 에러 처리를 담당하며, 모든 페이지에서 발생할 수 있는 오류를 관리합니다.

// 부적절한 코드
export default function GlobalError() {
    return (
        <html>
            <body>
                <h2>Something went wrong!</h2>
            </body>
        </html>
    );
}

// 적절한 코드
export default function GlobalErrorWithMessage({ error, reset }) {
    return (
        <html>
            <body>
                <h2>Something went wrong!</h2>
                <p>{error.message}</p> {/* 에러 메시지 표시 */}
                <button onClick={reset}>Try again</button> {/* 재시도 버튼 */}
            </body>
        </html>
    );
}

 

6. API 호출 시 에러 처리 (Next.js)

API 호출 시에는 try/catch 블록을 사용하여 오류를 적절하게 처리해야 합니다. 이를 통해 사용자에게 유용한 피드백을 제공하고, 애플리케이션이 예기치 않게 종료되는 것을 방지할 수 있습니다.

// 부적절한 코드
const apiCallWithoutErrorHandling = async () => {
    const response = await fetch('/api/data');
    if (!response.ok) { /* 오류 처리 없음 */ }
};

// 적절한 코드
const apiCallWithErrorHandling = async () => {
    try {
        const response = await fetch('/api/data');
        if (!response.ok) throw new Error('Network response was not ok');
    } catch (error) {
        console.error('Fetch error:', error);
    }
};

 

7. ESLint 규칙 준수 (ESLint)

ESLint는 코드 품질을 유지하는 데 중요한 역할을 합니다. TypeScript와 함께 사용할 때는 규칙에 따라 코드를 작성해야 하며, 경고가 발생하지 않도록 주의해야 합니다. 예를 들어, 빈 객체 타입 {} 대신 Record<string, never> 또는 unknown을 사용하는 것이 좋습니다.

// 부적절한 코드
const myFunction = (): void => { /* ... */ }; // 빈 객체 타입 사용
const result: {} = {}; // 경고 발생

// 적절한 코드
const myFunctionWithProperType = (): void => { /* ... */ };
const result: Record<string, never> = {}; // 명확한 타입 사용

 

 

마치며

Next.js, TypeScript, ESLint를 함께 사용할 때는 위와 같은 점들을 유의하여 개발하면 더욱 안정적이고 효율적인 애플리케이션을 만들 수 있습니다. 각 도구의 특성과 규칙을 잘 이해하고 적용함으로써 코드 품질과 사용자 경험을 향상시킬 수 있습니다. 부적절한 코드와 적절한 코드를 비교함으로써 올바른 코딩 패턴을 익히는 데 도움이 되기를 바랍니다.

Comments