TypeScriptとReactの実践的な使い方
TypeScriptとReactの実践的な使い方
TypeScriptとReactを組み合わせることで、型安全で保守性の高いアプリケーションを開発できます。
TypeScriptの基本的な型定義
コンポーネントのProps
interface UserProps {
name: string;
age: number;
email?: string; // オプショナルなプロパティ
onUpdate: (id: number) => void; // 関数の型定義
}
const UserProfile: React.FC<UserProps> = ({ name, age, email, onUpdate }) => {
return (
<div>
<h2>{name}</h2>
<p>Age: {age}</p>
{email && <p>Email: {email}</p>}
<button onClick={() => onUpdate(1)}>Update</button>
</div>
);
};
カスタムフック
interface UseCounterResult {
count: number;
increment: () => void;
decrement: () => void;
}
function useCounter(initialValue: number = 0): UseCounterResult {
const [count, setCount] = useState(initialValue);
return {
count,
increment: () => setCount(prev => prev + 1),
decrement: () => setCount(prev => prev - 1)
};
}
Reactの実践的なパターン
コンテキストの使用
interface ThemeContext {
isDark: boolean;
toggleTheme: () => void;
}
const ThemeContext = React.createContext<ThemeContext | undefined>(undefined);
export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [isDark, setIsDark] = useState(false);
return (
<ThemeContext.Provider value={{
isDark,
toggleTheme: () => setIsDark(prev => !prev)
}}>
{children}
</ThemeContext.Provider>
);
};
エラー境界
class ErrorBoundary extends React.Component<
{ children: React.ReactNode },
{ hasError: boolean }
> {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
パフォーマンス最適化
メモ化の活用
interface ExpensiveComponentProps {
data: Array<{ id: number; name: string }>;
onItemClick: (id: number) => void;
}
const ExpensiveComponent = React.memo<ExpensiveComponentProps>(
({ data, onItemClick }) => {
return (
<ul>
{data.map(item => (
<li key={item.id} onClick={() => onItemClick(item.id)}>
{item.name}
</li>
))}
</ul>
);
}
);
カスタムフックでのキャッシュ
function useDataFetching<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
const result = await response.json();
setData(result);
} catch (e) {
setError(e as Error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
ベストプラクティス
- コンポーネントの分割と責務の分離
- 適切な型定義の活用
- パフォーマンス最適化の実装
- エラーハンドリングの徹底
- テストの作成(Jest + React Testing Library)
TypeScriptとReactを組み合わせることで、開発時のエラーを早期に発見し、メンテナンス性の高いコードを書くことができます。また、IDEのサポートも充実し、開発効率が大幅に向上します。