ホームページ > 記事 > ウェブフロントエンド > React コンポーネントを分解するためのいくつかの高度な方法
React コンポーネントは無限に魔法がかかり、非常に柔軟です。コンポーネントの設計では、さまざまなトリックを試すことができます。しかし、コンポーネントの単一責任原則を確実にすることは非常に重要です。これにより、コンポーネントがよりシンプルで保守しやすくなり、さらに重要なことに、コンポーネントがより再利用可能になります。この記事では主に、React コンポーネントを分解するいくつかの高度な方法を紹介し、役立つことを願っています。
ただし、複雑で肥大化した React コンポーネントをどのように分解するかは、簡単な問題ではない可能性があります。この記事では、React コンポーネントを浅いものから深いものへと分解する 3 つの方法を紹介します。
これは考えるのが最も簡単な方法です。コンポーネントが多くの要素をレンダリングする場合、これらの要素のレンダリング ロジックを分離する必要があります。最も速い方法は、render() メソッドを複数のサブレンダリング メソッドに分割することです。
次の例を見ると、より直感的になります:
class Panel extends React.Component { renderHeading() { // ... } renderBody() { // ... } render() { return ( <div> {this.renderHeading()} {this.renderBody()} </div> ); } }
注意深い読者は、これが実際にはコンポーネント自体を分解していないことがすぐにわかりますが、Panel コンポーネントは元の状態、props、およびクラス メソッドを維持しています。
コンポーネントの複雑さを実際に軽減するにはどうすればよいでしょうか?いくつかのサブコンポーネントを作成する必要があります。現時点では、React の最新バージョンでサポートおよび推奨されている機能コンポーネント/ステートレス コンポーネントを採用することは間違いなく良い試みとなるでしょう:
const PanelHeader = (props) => ( // ...);const PanelBody = (props) => ( // ...);class Panel extends React.Component { render() { return ( <div> // Nice and explicit about which props are used <PanelHeader title={this.props.title}/> <PanelBody content={this.props.content}/> </div> ); } }
以前の方法と比較して、この微妙な改善は革命的です。
PanelHeader とPanelBody という 2 つの新しいユニット コンポーネントを作成しました。これによりテストが便利になり、さまざまなコンポーネントを個別に直接テストできます。同時に、React の新しいアルゴリズム エンジン React Fiber の助けにより、2 つのユニット コンポーネントのレンダリング効率が大幅に向上すると楽観的に期待されています。
問題の出発点に戻り、コンポーネントが肥大化して複雑になるのはなぜでしょうか。 1 つは、ネストされたレンダリング要素が多数あること、もう 1 つは、コンポーネント内に多くの変更があるか、複数の構成があることです。
この時点で、コンポーネントをテンプレートに変換できます。親コンポーネントはテンプレートに似ており、さまざまな構成のみに焦点を当てています。
より明確に理解できるように、例を挙げてみましょう。
たとえば、複数の動作またはイベントを持つ Comment コンポーネントがあります。
同時に、コンポーネントによって表示される情報は、ユーザーの ID に応じて変わります。
ユーザーがこのコメントの作成者であるかどうか
このコメントが正しく保存されているかどうか。権限
お待ちください...
により、このコンポーネントの表示動作が異なります。
class CommentTemplate extends React.Component { static propTypes = { // Declare slots as type node metadata: PropTypes.node, actions: PropTypes.node, }; render() { return ( <div> <CommentHeading> <Avatar user={...}/> // Slot for metadata <span>{this.props.metadata}</span> </CommentHeading> <CommentBody/> <CommentFooter> <Timestamp time={...}/> // Slot for actions <span>{this.props.actions}</span> </CommentFooter> </div> ... ) } }現時点では、実際の Comment コンポーネントは次のように構成されています:
class Comment extends React.Component { render() { const metadata = this.props.publishTime ? <PublishTime time={this.props.publishTime} /> : <span>Saving...</span>; const actions = []; if (this.props.isSignedIn) { actions.push(<LikeAction />); actions.push(<ReplyAction />); } if (this.props.isAuthor) { actions.push(<DeleteAction />); } return <CommentTemplate metadata={metadata} actions={actions} />; } }メタデータとアクションは、実際には特定の状況下でレンダリングする必要がある React 要素です。 例: this.props.publishTime が存在する場合、メタデータは
class Document extends React.Component { componentDidMount() { ReactDOM.findDOMNode(this).addEventListener('click', this.onClick); } componentWillUnmount() { ReactDOM.findDOMNode(this).removeEventListener('click', this.onClick); } onClick = (e) => { // Naive check for <a> elements if (e.target.tagName === 'A') { sendAnalytics('link clicked', { // Specific information to be sent documentId: this.props.documentId }); } }; render() { // ... } }これにはいくつかの問題があります: 独自のメインロジックに加えて、メインページを表示し、関連コンポーネント Document 他の統計ロジックがあります Document コンポーネントのライフサイクル関数に他のロジックがある場合、このコンポーネントはより曖昧で不合理になります
function withLinkAnalytics(mapPropsToData, WrappedComponent) { class LinkAnalyticsWrapper extends React.Component { componentDidMount() { ReactDOM.findDOMNode(this).addEventListener('click', this.onClick); } componentWillUnmount() { ReactDOM.findDOMNode(this).removeEventListener('click', this.onClick); } onClick = (e) => { // Naive check for <a> elements if (e.target.tagName === 'A') { const data = mapPropsToData ? mapPropsToData(this.props) : {}; sendAnalytics('link clicked', data); } }; render() { // Simply render the WrappedComponent with all props return <WrappedComponent {...this.props} />; } } ... }withLinkAnalytics 関数は、WrappedComponent コンポーネント自体は変更せず、ましてや WrappedComponent コンポーネントの動作は変更しないことに注意してください。 。代わりに、新しいラップされたコンポーネントが返されます。実際の使用法は次のとおりです:
class Document extends React.Component { render() { // ... } } export default withLinkAnalytics((props) => ({ documentId: props.documentId }), Document);
高次コンポーネントの存在は、React コミュニティでは、react-redux、styled-components、react-intl などが一般的にこのアプローチを採用しています。再構成クラス ライブラリは高次のコンポーネントを利用し、それらを前進させて「脳を拡張する」ことを実現していることは言及する価値があります。
React とその周辺コミュニティの台頭により、関数型プログラミングが人気になり、求められるようになりました。分解と合成の考え方は学ぶ価値があると思います。同時に、開発と設計に対する提案は、通常の状況では、ためらわずにコンポーネントをより小さく単純なコンポーネントに分割することです。これにより、堅牢性と再利用につながる可能性があります。
関連する推奨事項:
以上がReact コンポーネントを分解するためのいくつかの高度な方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。