Layout Components는 애플리케이션의 레이아웃을 정의하는 컴포넌트입니다. 일반적으로 Header, Footer, Sidebar, Main Content 영역 등을 포함합니다.
import React, { FC, ReactNode } from 'react';
type LayoutProps = {
children: ReactNode;
};
const Layout: FC<LayoutProps> = ({ children }) => {
return (
<div>
<header>Header</header>
<aside>Sidebar</aside>
<main>{children}</main>
<footer>Footer</footer>
</div>
);
};
export default Layout;
import React from 'react';
import Layout from './Layout';
const App: React.FC = () => {
return (
<Layout>
<h1>Main Content</h1>
<p>This is the main content of the application.</p>
</Layout>
);
};
export default App;
Controlled Components는 폼 요소의 상태를 React 컴포넌트가 제어하는 방식입니다. 입력값을 state로 관리합니다.
import React, { useState, ChangeEvent, FC } from 'react';
const ControlledInput: FC = () => {
const [value, setValue] = useState<string>('');
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value);
};
return (
<input type="text" value={value} onChange={handleChange} />
);
};
export default ControlledInput;
import React from 'react';
import ControlledInput from './ControlledInput';
const App: React.FC = () => {
return (
<div>
<h1>Controlled Input Example</h1>
<ControlledInput />
</div>
);
};
export default App;
Custom Hooks는 재사용 가능한 로직을 Hook 형태로 추출한 것입니다. 비즈니스 로직이나 상태 관리를 캡슐화할 때 유용합니다.
import { useState, useEffect } from 'react';
const useFetchData = (url: string) => {
const [data, setData] = useState<any>(null);
const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
const result = await response.json();
setData(result);
} catch (error) {
console.error('Error fetching data:', error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading };
};
export default useFetchData;
import React from 'react';
import useFetchData from './useFetchData';
const DataComponent: React.FC = () => {
const { data, loading } = useFetchData('https://api.example.com/data');
if (loading) {
return <div>Loading...</div>;
}
return (
<div>
<h1>Fetched Data</h1>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
};
export default DataComponent;
Functional Programming 패러다임을 React에서 활용하는 방법입니다. 주로 순수 함수, 고차 함수 등을 활용합니다.
import React, { FC } from 'react';
const numbers: number[] = [1, 2, 3, 4, 5];
// 순수함수
const double = (num: number): number => num * 2;
const FunctionalComponent: FC = () => {
const doubledNumbers = numbers.map(double);
return (
<div>
{doubledNumbers.map((num, index) => (
<div key={index}>{num}</div>
))}
</div>
);
};
export default FunctionalComponent;
import React from 'react';
import FunctionalComponent from './FunctionalComponent';
const App: React.FC = () => {
return (
<div>
<h1>Functional Programming Example</h1>
<FunctionalComponent />
</div>
);
};
export default App;
서버에서 받아온 데이터를 화면에 맞게 변환하는 경우의 예시
import React, { FC, useEffect, useState } from 'react';
interface User {
id: number;
firstName: string;
lastName: string;
}
interface UserViewModel {
id: number;
fullName: string;
}
const transformUser = (user: User): UserViewModel => ({
id: user.id,
fullName: `${user.firstName} ${user.lastName}`,
});
const UserList: FC = () => {
const [users, setUsers] = useState<UserViewModel[]>([]);
useEffect(() => {
fetch('/api/users')
.then(response => response.json())
.then((data: User[]) => {
const transformedData = data.map(transformUser);
setUsers(transformedData);
});
}, []);
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.fullName}</li>
))}
</ul>
);
};
export default UserList;
HOC는 컴포넌트를 인자로 받아 새로운 컴포넌트를 반환하는 함수입니다. 컴포넌트의 로직을 재사용할 때 유용합니다.
import React, { ComponentType, FC } from 'react';
interface WithLoadingProps {
isLoading: boolean;
}
const withLoading = <P extends object>(Component: ComponentType<P>): FC<P & WithLoadingProps> => {
return ({ isLoading, ...props }: WithLoadingProps) => {
if (isLoading) {
return <div>Loading...</div>;
}
return <Component {...props as P} />;
};
};
type DataProps = {
data: string;
};
const DataComponent: FC<DataProps> = ({ data }) => {
return <div>{data}</div>;
};
const DataComponentWithLoading = withLoading(DataComponent);
export default DataComponentWithLoading;
import React from 'react';
import DataComponentWithLoading from './DataComponentWithLoading';
const App: React.FC = () => {
const [isLoading, setIsLoading] = React.useState<boolean>(true);
const [data, setData] = React.useState<string>('');
React.useEffect(() => {
setTimeout(() => {
setData('Here is some fetched data!');
setIsLoading(false);
}, 3000);
}, []);
return (
<div>
<h1>Higher Order Component Example</h1>
<DataComponentWithLoading isLoading={isLoading} data={data} />
</div>
);
};
export default App;
사용자의 목록을 가져와서 표시하는 간단한 애플리케이션을 만들 것입니다. 각 사용자 항목을 클릭하면 세부 정보를 보여주고, 로딩 상태를 표시하며, 검색 기능을 제공할 것입니다.
우리는 사용자의 목록을 가져와서 표시하는 간단한 애플리케이션을 만들 것입니다. 각 사용자 항목을 클릭하면 세부 정보를 보여주고, 로딩 상태를 표시하며, 검색 기능을 제공할 것입니다.
전체 레이아웃을 구성하는 컴포넌트를 정의합니다.
import React, { FC, ReactNode } from 'react';
type LayoutProps = {
children: ReactNode;
};
const Layout: FC<LayoutProps> = ({ children }) => {
return (
<div>
<header>Header</header>
<aside>Sidebar</aside>
<main>{children}</main>
<footer>Footer</footer>
</div>
);
};
export default Layout;
사용자 검색 입력을 처리하는 컴포넌트를 정의합니다.
import React, { FC, ChangeEvent, useState } from 'react';
interface SearchInputProps {
onSearch: (query: string) => void;
}
const SearchInput: FC<SearchInputProps> = ({ onSearch }) => {
const [query, setQuery] = useState('');
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
setQuery(event.target.value);
onSearch(event.target.value);
};
return <input type="text" value={query} onChange={handleChange} placeholder="Search users..." />;
};
export default SearchInput;
사용자 데이터를 가져오는 커스텀 훅을 정의합니다.
import { useState, useEffect } from 'react';
const useFetchUsers = (query: string) => {
const [users, setUsers] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchUsers = async () => {
setLoading(true);
try {
const response = await fetch(`https://api.example.com/users?search=${query}`);
const data = await response.json();
setUsers(data);
} catch (error) {
console.error('Error fetching users:', error);
} finally {
setLoading(false);
}
};
fetchUsers();
}, [query]);
return { users, loading };
};
export default useFetchUsers;
사용자 데이터를 변환하고 필터링하는 순수 함수를 정의합니다.
interface User {
id: number;
firstName: string;
lastName: string;
email: string;
}
const filterUsers = (users: User[], query: string): User[] => {
return users.filter(user =>
`${user.firstName} ${user.lastName}`.toLowerCase().includes(query.toLowerCase())
);
};
const transformUser = (user: User) => ({
id: user.id,
fullName: `${user.firstName} ${user.lastName}`,
email: user.email,
});
export { filterUsers, transformUser };
로딩 상태를 처리하는 HOC를 정의합니다.
import React, { ComponentType, FC } from 'react';
interface WithLoadingProps {
isLoading: boolean;
}
const withLoading = <P extends object>(Component: ComponentType<P>): FC<P & WithLoadingProps> => {
return ({ isLoading, ...props }: WithLoadingProps) => {
if (isLoading) {
return <div>Loading...</div>;
}
return <Component {...props as P} />;
};
};
export default withLoading;
모든 패턴을 통합하여 애플리케이션을 구성합니다.
import React, { FC, useState } from 'react';
import Layout from './Layout';
import SearchInput from './SearchInput';
import useFetchUsers from './useFetchUsers';
import withLoading from './withLoading';
import { filterUsers, transformUser } from './utils';
interface User {
id: number;
fullName: string;
email: string;
}
interface UserListProps {
users: User[];
}
const UserList: FC<UserListProps> = ({ users }) => (
<ul>
{users.map(user => (
<li key={user.id}>
<strong>{user.fullName}</strong>
<p>{user.email}</p>
</li>
))}
</ul>
);
const UserListWithLoading = withLoading(UserList);
const App: FC = () => {
const [query, setQuery] = useState('');
const { users, loading } = useFetchUsers(query);
const filteredUsers = filterUsers(users.map(transformUser), query);
return (
<Layout>
<SearchInput onSearch={setQuery} />
<UserListWithLoading isLoading={loading} users={filteredUsers} />
</Layout>
);
};
export default App;