React: 関数コンポーネント vs クラスコンポーネント - それぞれのメリットとデメリット
Reactにおける function App()
と class App extends Component
の違い
- 関数コンポーネント:
function App()
のように定義します。 - クラスコンポーネント:
class App extends Component
のように定義します。
どちらもコンポーネントを作成する方法ですが、それぞれ以下のような違いがあります。
構文
- クラスコンポーネントは、より詳細な制御が可能ですが、記述量が多くなります。
React.Component
を継承し、render
メソッドを定義する必要があります。 - 関数コンポーネントは、簡潔で分かりやすいのが特徴です。引数としてpropsを受け取り、JSXを返します。
状態管理
- クラスコンポーネントは、コンポーネントの内部ステートを直接管理できます。
this.state
を使用してステートにアクセスし、setState
メソッドを使用して更新します。 - 関数コンポーネントは、ステートを直接管理できません。ステートを管理したい場合は、
useState
フックを使用する必要があります。
ライフサイクルメソッド
- クラスコンポーネントは、ライフサイクルメソッドを直接定義できます。
- 関数コンポーネントは、ライフサイクルメソッドをフックを使用して呼び出します。
- クラスコンポーネントは、より複雑なロジックを処理するのに適しています。
- 関数コンポーネントは、クラスコンポーネントよりもパフォーマンスが優れている傾向があります。
どちらを選ぶべきか
近年では、関数コンポーネントの方がシンプルで使いやすいことから、新規プロジェクトでは関数コンポーネントを使用するのが一般的です。
しかし、以下のような場合は、クラスコンポーネントの方が適している場合があります。
- 高度なパフォーマンスが求められる場合
- ライフサイクルメソッドを多用する必要がある場合
- ステートが複雑な場合
関数コンポーネント
function Greeting(props) {
return (
<h1>こんにちは、{props.name}さん!</h1>
);
}
class Greeting extends React.Component {
render() {
return (
<h1>こんにちは、{this.props.name}さん!</h1>
);
}
}
この例では、Greeting
という名前のクラスコンポーネントを定義しています。このコンポーネントは、props
プロパティを受け取り、その中の name
プロパティにアクセスして挨拶文に含めて返します。
説明
- クラスコンポーネントは、
this.props
を使用してプロパティにアクセスする必要があります。 - 関数コンポーネントは、より簡潔で分かりやすい構文です。
- 関数コンポーネントとクラスコンポーネントは、どちらも
name
というプロパティを受け取り、挨拶文を返します。
高階コンポーネントは、既存のコンポーネントをラップして、機能を追加する手法です。既存のコンポーネントのコードを変更することなく、機能を追加できるため、再利用性やコードの保守性を高めることができます。
const withCounter = (WrappedComponent) => {
class WithCounter extends React.Component {
state = {
count: 0
};
increment = () => {
this.setState((prevState) => ({ count: prevState.count + 1 }));
};
render() {
return (
<WrappedComponent {...this.props} count={this.state.count} increment={this.increment} />
);
}
}
return WithCounter;
};
const MyButton = ({ count, increment }) => (
<button onClick={increment}>クリック ({count})</button>
);
const ButtonWithCounter = withCounter(MyButton);
この例では、withCounter
という高階コンポーネントを作成しています。このコンポーネントは、引数として既存のコンポーネントを受け取り、そのコンポーネントに count
と increment
というプロパティを追加します。 MyButton
コンポーネントを withCounter
でラップすることで、ButtonWithCounter
という新しいコンポーネントが作成されます。この ButtonWithCounter
コンポーネントは、クリックされた回数を表示し、クリック時に回数をカウントアップする機能が追加されています。
React Context
React Contextは、コンポーネントツリー全体で共有するデータや機能を提供する仕組みです。コンポーネント間のプロパティの渡し渡しをシンプルにし、コードの再利用性を高めることができます。
const ThemeContext = React.createContext({
theme: 'light'
});
const App = () => (
<ThemeContext.Provider value={{ theme: 'dark' }}>
<MyComponent />
</ThemeContext.Provider>
);
const MyComponent = () => (
<ThemeContext.Consumer>
{({ theme }) => (
<div className={`app ${theme}`}>
<h1>My Component</h1>
</div>
)}
</ThemeContext.Consumer>
);
この例では、ThemeContext
というコンテキストを作成しています。このコンテキストは、theme
というプロパティを持ち、その値は light
または dark
になります。 App
コンポーネントは、ThemeContext.Provider
を使用して、theme
の値を dark
に設定します。 MyComponent
コンポーネントは、ThemeContext.Consumer
を使用して、theme
の値を取得し、その値に応じてスタイルを適用します。
カスタムフック (Custom Hooks)
カスタムフックは、再利用可能なロジックをカプセル化するために使用される関数です。ステートやライフサイクルなどの機能を抽象化することで、コンポーネントコードを簡潔で分かりやすくすることができます。
const useCounter = () => {
const [count, setCount] = React.useState(0);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
return { count, increment, decrement };
};
const MyComponent = () => {
const { count, increment, decrement } = useCounter();
return (
<div>
<p>カウント: {count}</p>
<button onClick={increment}>増やす</button>
<button onClick={decrement}>減らす</button>
</div>
);
};
この例では、useCounter
というカスタムフックを作成しています。このフックは、count
というステートと、increment
と decrement
というアクション関数を提供します。 MyComponent
コンポーネントは、useCounter
フックを使用して、count
と increment
と decrement
を取得し、それらを UI に表示したり、アクションを実行したりします。
これらの方法は、それぞれ異なる利点と欠点があります。プロジェクトの要件や開発者の好みによって、適切な方法を選択することが重要です。
reactjs