ReactとTypeScriptでHTML要素を拡張しつつpropsを保持する
前提
- TSXはTypeScriptの拡張で、JavaScriptX構文を使用し、JSX構文をTypeScriptに統合します。
- TypeScriptはJavaScriptのスーパーセットで、静的な型付けを提供します。
- ReactはJavaScriptライブラリで、UIの構築に使用されます。
目的
- 拡張した要素にpropsを伝達したい。
- ReactのHTML要素を拡張して、独自の機能を追加したい。
方法
-
カスタムフックの作成
useState
やuseEffect
などのReactのフックを組み合わせて、必要なロジックを実装します。- カスタムフックは、再利用可能なロジックをカプセル化し、コンポーネントのコードを整理します。
-
拡張コンポーネントの作成
- 拡張したいHTML要素をベースに、新しいコンポーネントを作成します。
- カスタムフックを呼び出し、必要な処理を行います。
- propsを適切に伝達し、元のHTML要素の機能を保持します。
コード例
// カスタムフック
function useCounter() {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
return { count, increment };
}
// 拡張コンポーネント
function EnhancedButton({ children, ...props }) {
const { count, increment } = useCounter();
return (
<button {...props} onClick={increment}>
{children} ({count})
</button>
);
}
解説
onClick
ハンドラーでincrement
関数を呼び出し、カウンタの値を更新します。...props
は、元のbutton
要素に渡されたpropsをすべて受け取るために使用されます。EnhancedButton
コンポーネントは、button
要素を拡張します。useCounter
フックは、カウンタの値を管理するためのロジックを提供します。
ポイント
- propsの伝達を適切に行うことで、柔軟性のあるコンポーネントを作成できます。
- 拡張コンポーネントは、元のHTML要素の機能を保持しつつ、独自の機能を追加します。
- カスタムフックは、コンポーネントのロジックを再利用可能にします。
- TypeScriptの型付けを活用することで、コードの信頼性と保守性を向上させることができます。
- 複雑な拡張が必要な場合は、クラスコンポーネントを使用することもできますが、一般的には関数コンポーネントとカスタムフックが推奨されます。
props
を直接アクセスし、独自のロジックを実装します。- Reactのクラスコンポーネントを使用し、
render
メソッドでHTML要素を拡張できます。
class EnhancedButton extends React.Component<{ children?: React.ReactNode }> {
state = { count: 0 };
increment = () => this.setState({ count: this.state.count + 1 });
render() {
return (
<button onClick={this.increment}>
{this.props.children} ({this.state.count})
</button>
);
}
}
HOC (Higher-Order Component)
props
を伝達し、拡張されたコンポーネントを返します。- 他のコンポーネントをラップして、新たな機能を追加する関数です。
function withCounter(WrappedComponent) {
return class EnhancedComponent extends React.Component {
state = { count: 0 };
increment = () => this.setState({ count: this.state.count + 1 });
render() {
return (
<WrappedComponent {...this.props}>
{this.props.children} ({this.state.count})
</WrappedComponent>
);
}
};
}
const EnhancedButton = withCounter(Button);
Render Props
- コンポーネントを関数として受け取り、その関数にpropsを渡すことで、子コンポーネントにデータや処理を提供します。
function Counter({ children }) {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
return children({ count, increment });
}
function EnhancedButton({ children }) {
return (
<Counter>
{({ count, increment }) => (
<button onClick={increment}>
{children} ({count})
</button>
)}
</Counter>
);
}
選択の基準
- Render Props
柔軟なデータの伝達や子コンポーネントの制御が必要な場合に使用します。 - HOC
複数のコンポーネントに共通の機能を追加したいときに便利です。 - クラスコンポーネント
ライフサイクルメソッドや複雑な状態管理が必要な場合に使用します。 - 関数コンポーネントとカスタムフック
シンプルな拡張や状態管理に適しています。
注意
- HOCやRender Propsは、特定のユースケースで活用することができます。
- クラスコンポーネントは、必要に応じて使用しますが、過度に複雑なコンポーネントは避けるようにしましょう。
- 現代のReact開発では、関数コンポーネントとカスタムフックが主流となっています。
reactjs typescript tsx