Reactでアコーディオンコンポーネントを構築する方法
序章
楽器のアコーディオンは圧縮および拡張します。 グラフィカル制御要素のアコーディオンも同様に折りたたみおよび拡張します。 これは、大きなコンテンツを分割し、ユーザーが自分に関連するセクションに集中できるようにするためのソリューションになります。
tabsコンポーネントと同様に、アコーディオンコンポーネントは、開閉を切り替えることができるさまざまなセクションで構成されています。 タブコンポーネントとは異なり、アコーディオンはコンテンツの複数のセクションを同時に表示することをサポートできます。
この記事では、開いたり閉じたりすることができるセクションを備えた、シンプルで再利用可能なアコーディオンコンポーネントを作成します。 次に、コンポーネントを変更して、一度に複数のセクションを開き、デフォルトで開くセクションを指定できるようにします。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- Node.jsはローカルにインストールされます。これは、Node.jsのインストール方法とローカル開発環境の作成に従って実行できます。
- Reactにある程度精通している。 React.jsシリーズのコーディング方法をご覧ください。
このチュートリアルは、ノードv16.6.2、npm
v7.21.0、およびreact
v17.0.2で検証されました。
ステップ1—プロジェクトの設定
このステップでは、 Create ReactAppを使用して新しいプロジェクトを作成します。 次に、プロジェクトのブートストラップ時にインストールされたサンプルプロジェクトと関連ファイルを削除します。
まず、新しいプロジェクトを作成します。 ターミナルで次のスクリプトを実行し、create-react-app
を使用して新しいプロジェクトをインストールします。
- npx create-react-app react-accordion-component
プロジェクトが終了したら、次のディレクトリに移動します。
- cd react-accordion-component
新しいターミナルタブまたはウィンドウで、 CreateReactApp開始スクリプトを使用してプロジェクトを開始します。 ブラウザは変更時に自動更新されるため、作業中はこのスクリプトを実行したままにします。
- npm start
これにより、ローカルで実行されているサーバーが起動します。 プロジェクトがブラウザウィンドウで開かなかった場合は、http://localhost:3000/
にアクセスしてプロジェクトを開くことができます。 これをリモートサーバーから実行している場合、アドレスはhttp://your_domain:3000
になります。
ブラウザには、CreateReactAppの一部として含まれているテンプレートReactアプリケーションが読み込まれます。
完全に新しいカスタムコンポーネントのセットを構築するので、空のプロジェクトを作成できるように、ボイラープレートコードをクリアすることから始める必要があります。
まず、テキストエディタでsrc/App.js
を開きます。 これは、ページに挿入されるルートコンポーネントです。 すべてのコンポーネントはここから始まります。 App.js
の詳細については、 Create ReactAppを使用してReactプロジェクトをセットアップする方法を参照してください。
次のようなファイルが表示されます。
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
import logo from './logo.svg';
の行を削除します。 次に、return
ステートメントのすべてを置き換えて、div
タグのセットとh1
を返します。 これにより、アコーディオンデモを表示するh1
を返す有効なページが表示されます。 最終的なコードは次のようになります。
import './App.css';
function App() {
return (
<div>
<h1>Accordion Demo</h1>
</div>
);
}
export default App;
テキストエディタを保存して終了します。
最後に、ロゴを削除します。 アプリケーションで使用することはありません。作業中に未使用のファイルを削除する必要があります。 長期的には混乱からあなたを救うでしょう。
ターミナルウィンドウで、次のコマンドを入力してロゴを削除します。
- rm src/logo.svg
プロジェクトが設定されたので、最初のコンポーネントを作成できます。
ステップ2—コンポーネントの構築
3つのコンポーネントを作成します。
Accordion
:セクションコンポーネントを保持し、開いているセクションと閉じているセクションを管理します。AccordionSection
:クリック可能なセクションのタイトル、セクションが開いているときのセクションの内容を表示し、クリックイベントについてAccordion
に報告します。App
:すべてを実際の例に結び付けるコンポーネント!
Accordion
コンポーネント内のセクションは、AccordionSection
内のクリック可能な領域に使用されるlabel
属性を受け取る<div>
タグになります。成分。
最も内側のコンポーネントAccordionSection
を作成することから始めましょう。
import React from 'react';
import PropTypes from 'prop-types';
class AccordionSection extends React.Component {
static propTypes = {
children: PropTypes.instanceOf(Object).isRequired,
isOpen: PropTypes.bool.isRequired,
label: PropTypes.string.isRequired,
onClick: PropTypes.func.isRequired,
};
onClick = () => {
this.props.onClick(this.props.label);
};
render() {
const {
onClick,
props: { isOpen, label },
} = this;
return (
<div
style={{
background: isOpen ? '#fae042' : '#6db65b',
border: '1px solid #008f68',
padding: '5px 10px',
}}
>
<div onClick={onClick} style={{ cursor: 'pointer' }}>
{label}
<div style={{ float: 'right' }}>
{!isOpen && <span>▲</span>}
{isOpen && <span>▼</span>}
</div>
</div>
{isOpen && (
<div
style={{
background: '#6db65b',
border: '2px solid #008f68',
marginTop: 10,
padding: '10px 20px',
}}
>
{this.props.children}
</div>
)}
</div>
);
}
}
export default AccordionSection;
このコンポーネントは、セクションのクリック可能なタイトルを作成するlabel
プロパティを受け取ります。 onClick
イベントハンドラープロパティは、ラベルがクリックされた場合に親コンポーネントに報告するために使用されます。
親コンポーネントは、どのセクションが開いているか閉じているかを追跡し、ステータスをブールプロパティisOpen
としてAccordionSection
にフィードバックします。
AccordionSection
の子コンポーネントは、セクションが開くように切り替えられ、プロパティisOpen
がtrueの場合にのみ表示されます。
セクションのコンポーネントができたので、これらのセクションを格納し、開いたセクションまたは閉じたセクションの状態を管理するコンポーネントが必要です。
import React from 'react';
import PropTypes from 'prop-types';
import AccordionSection from './AccordionSection';
class Accordion extends React.Component {
static propTypes = {
children: PropTypes.instanceOf(Object).isRequired,
};
constructor(props) {
super(props);
const openSections = {};
this.state = { openSections };
}
onClick = label => {
const {
state: { openSections },
} = this;
const isOpen = !!openSections[label];
this.setState({
openSections: {
[label]: !isOpen
}
});
};
render() {
const {
onClick,
props: { children },
state: { openSections },
} = this;
return (
<div style={{ border: '2px solid #008f68' }}>
{children.map(child => (
<AccordionSection
isOpen={!!openSections[child.props.label]}
label={child.props.label}
onClick={onClick}
>
{child.props.children}
</AccordionSection>
))}
</div>
);
}
}
export default Accordion;
素晴らしい! Accordion
コンポーネントは、インタラクティブなAccordionSection
コンポーネントの作成に使用される子ノードを受け取ります。
このコンポーネントは、どのセクションが切り替えられて開かれたかを追跡しますが、一度に開いているセクションは1つだけ追跡します(現時点では)。
Accordion
およびAccordionSection
コンポーネントを作成したら、App
コンポーネントを作成して、動作を確認できます。
アコーディオンのデモでは、ワニに関するいくつかの事実を含む2つの子コンポーネントを含むAccordion
を作成します。
import Accordion from './Accordion';
function App() {
return (
<div>
<h1>Accordion Demo</h1>
<Accordion>
<div label='Alligator Mississippiensis'>
<p>
<strong>Common Name:</strong> American Alligator
</p>
<p>
<strong>Distribution:</strong> Texas to North Carolina, US
</p>
<p>
<strong>Endangered Status:</strong> Currently Not Endangered
</p>
</div>
<div label='Alligator Sinensis'>
<p>
<strong>Common Name:</strong> Chinese Alligator
</p>
<p>
<strong>Distribution:</strong> Eastern China
</p>
<p>
<strong>Endangered Status:</strong> Critically Endangered
</p>
</div>
</Accordion>
</div>
);
}
export default App;
Accordion
には2つのセクションがあり、クリックして開くと、さまざまな種類のワニに関するいくつかの事実が表示されます。
ステップ3—複数のオープンアコーディオンをサポートする
これまでに作成したものはすべて使用可能ですが、一度に開くことができるセクションは1つだけであり、デフォルトではすべてのセクションが折りたたまれているため、多少制限があります。
同時に開いている複数のセクションのサポートを追加するには、allowMultipleOpen
という名前のプロパティをAccordion
コンポーネントに追加します。このプロパティは、複数のセクションを許可するかどうかをアコーディオンに通知するために使用されます。オープンに。
有効にすると、状態は、操作されたセクションで状態を完全に上書きするのではなく、個々のキーのtrue/falseを切り替えます。
そこにいる間に、子ノードでisOpen
プロパティをチェックするロジックを追加できます。 存在する場合、オープン状態は初期化され、セクションはすでにオープンとしてマークされています。
import React from 'react';
import PropTypes from 'prop-types';
import AccordionSection from './AccordionSection';
class Accordion extends React.Component {
static propTypes = {
allowMultipleOpen: PropTypes.bool,
children: PropTypes.instanceOf(Object).isRequired,
};
constructor(props) {
super(props);
const openSections = {};
this.props.children.forEach(child => {
if (child.props.isOpen) {
openSections[child.props.label] = true;
}
});
this.state = { openSections };
}
onClick = label => {
const {
props: { allowMultipleOpen },
state: { openSections },
} = this;
const isOpen = !!openSections[label];
if (allowMultipleOpen) {
this.setState({
openSections: {
...openSections,
[label]: !isOpen
}
});
} else {
this.setState({
openSections: {
[label]: !isOpen
}
});
}
};
render() {
const {
onClick,
props: { children },
state: { openSections },
} = this;
return (
<div style={{ border: '2px solid #008f68' }}>
{children.map(child => (
<AccordionSection
isOpen={!!openSections[child.props.label]}
label={child.props.label}
onClick={onClick}
>
{child.props.children}
</AccordionSection>
))}
</div>
);
}
}
export default Accordion;
Accordion
で新しいパラメーターを受け入れる準備ができたら、App
コンポーネントを更新してプロパティを渡し、複数のセクションを開くことができるようにし、最初のセクションをデフォルトで開くようにフラグを立てます。
import Accordion from './Accordion';
function App() {
return (
<div>
<h1>Accordion Demo</h1>
<Accordion allowMultipleOpen>
<div label='Alligator Mississippiensis' isOpen>
<p>
<strong>Common Name:</strong> American Alligator
</p>
<p>
<strong>Distribution:</strong> Texas to North Carolina, US
</p>
<p>
<strong>Endangered Status:</strong> Currently Not Endangered
</p>
</div>
<div label='Alligator Sinensis'>
<p>
<strong>Common Name:</strong> Chinese Alligator
</p>
<p>
<strong>Distribution:</strong> Eastern China
</p>
<p>
<strong>Endangered Status:</strong> Critically Endangered
</p>
</div>
</Accordion>
</div>
);
}
export default App;
手に負えないコンテンツを手なずけるのに役立つ再利用可能なアコーディオンコンポーネントがあります。
結論
この記事では、開いたり閉じたりすることができるセクションを備えた、シンプルで再利用可能なアコーディオンコンポーネントを作成しました。
最も複雑なシナリオでも満たすようにこれらのアコーディオンをネストして、学習を続けてください。
CodeSandbox で、この記事の実用的なデモとコードを見つけることができます。