# reactstrap を使ったコンポーネントのレンダリング制御

[GROWI](https://tips.weseek.co.jp/5e393927e848c600487d6a01) は [bootstrap](https://tips.weseek.co.jp/5e3936ebe848c600487d69f6) を用いスタイルを制御しています。  
基本的にはバニラな [bootstrap](https://tips.weseek.co.jp/5e3936ebe848c600487d69f6) を用い、なるべく reactstrap を用いないのが [GROWI チームの方針](https://tips.weseek.co.jp/5e3938c6e848c600487d69fa)です。

Bootstrap 4 化に際し、通知設定のページを [React](https://tips.weseek.co.jp/5e3930c8e848c600487d69ed) で構築することになりました。  

[該当のPR](https://github.com/weseek/growi/pull/1600)

## バニラな bootstrap を用いた実装

```js:NotificationSetting.jsx
  render() {

    return (
      <React.Fragment>
        <div className="notification-settings">
          <ul className="nav nav-tabs" role="tablist">
            <li className="active">
              <a href="#slack-configuration" data-toggle="tab" role="tab"><i className="icon-settings"></i> Slack Configuration</a>
            </li>
            <li>
              <a href="#user-trigger-notification" data-toggle="tab" role="tab"><i className="icon-settings"></i> User Trigger Notification</a>
            </li>
            <li>
              <a href="#global-notification" data-toggle="tab" role="tab"><i className="icon-settings"></i> Global Notification</a>
            </li>
          </ul>
          <div className="tab-content m-t-15">
            <div id="slack-configuration" className="tab-pane active" role="tabpanel">
              <SlackAppConfiguration />
            </div>
            <div id="user-trigger-notification" className="tab-pane" role="tabpanel">
              <UserTriggerNotification />
            </div>
            <div id="global-notification" className="tab-pane" role="tabpanel">
              <GlobalNotification />
            </div>
          </div>
        </div>
      </React.Fragment>
    );
  }
```

しかし、この実装だと各タブ内のコンポーネントがレンダリングしてしまいます。  
問題点としてはタブを開いていないのに、データを取得してしまいます。  
そのため、タブを開いた時にレンダリングする実装に変更する必要があります。

## reactstrap を用いた実装

```js:NotificationSetting.jsx
class NotificationSetting extends React.Component {

  constructor() {
    super();

    this.state = {
      activeTab: 'slack-configuration',
      // Prevent unnecessary rendering
      activeComponents: new Set(['slack-configuration']),
    };

    this.toggleActiveTab = this.toggleActiveTab.bind(this);
  }

  ~中略~

  toggleActiveTab(activeTab) {
    this.setState({
      activeTab, activeComponents: this.state.activeComponents.add(activeTab),
    });
  }

  render() {
    const { activeTab, activeComponents } = this.state;

    return (
      <React.Fragment>
        <Nav tabs>
          <NavItem>
            <NavLink
              className={`${activeTab === 'slack-configuration' && 'active'} `}
              onClick={() => { this.toggleActiveTab('slack-configuration') }}
            >
              <i className="icon-settings"></i> Slack Configuration
            </NavLink>
          </NavItem>
          <NavItem>
            <NavLink
              className={`${activeTab === 'user-trigger-notification' && 'active'} `}
              onClick={() => { this.toggleActiveTab('user-trigger-notification') }}
            >
              <i className="icon-settings"></i> User Trigger Notification
            </NavLink>
          </NavItem>
          <NavItem>
            <NavLink
              className={`${activeTab === 'global-notification' && 'active'} `}
              onClick={() => { this.toggleActiveTab('global-notification') }}
            >
              <i className="icon-settings"></i> Global Notification
            </NavLink>
          </NavItem>
        </Nav>
        <TabContent activeTab={activeTab}>
          <TabPane tabId="slack-configuration">
            {activeComponents.has('slack-configuration') && <SlackAppConfiguration />}
          </TabPane>
          <TabPane tabId="user-trigger-notification">
            {activeComponents.has('user-trigger-notification') && <UserTriggerNotification />}
          </TabPane>
          <TabPane tabId="global-notification">
            {activeComponents.has('global-notification') && <GlobalNotification />}
          </TabPane>
        </TabContent>
      </React.Fragment>
    );
  }

}
```

現在開いているタブと既にレンダーしたコンポーネントを state として管理します。  
なので各コンポーネントの render が走るのは 1 回目にタブを開いた時だけです。  
タブを切り替えても再度レンダリングされることはありません。  

`activeComponents` は配列ではなく [Set オブジェクト](https://tips.weseek.co.jp/5e4252bbdecd0a0049953aea) を用いているため、値が重複することはありません。



---

## Page Navigation

- Canonical URL: https://tips.weseek.co.jp/GROWI/reactstrap%20を使ったコンポーネントのレンダリング制御
- Permalink: https://tips.weseek.co.jp/5e424e61decd0a0049953ae1
- Parent: [GROWI](/5e393927e848c600487d6a01.md)
- Children: 0 total
- Total descendants: 0
- Siblings: 8 total
  - [GROWIでapiを叩いてみよう](/5e4d5253340a4f0049473d2b.md)
  - [GROWIにおけるBootstrap](/5e3938c6e848c600487d69fa.md)
  - [GROWIのバージョンを下げた時に、nodeのバージョンで怒られた時の対処法](/5f7c32e8b8f345004895b23e.md)
  - [SSOと仲良くなろう](/5f99372a04330d004832a02c.md)
  - [formのactionでPUTとDELETEが送れない件](/5e789d45a5e29a004842ba63.md)
  - [分割代入を使って見通しの良いコードを書こう](/5e3e6f19591d7f0048b3cc69.md)
  - [実例で見るpointer-eventsの使い方](/5e50df38839fe70048321573.md)
  - [故意の技術的負債から目を逸らさない](/5e71da49df47e40049fa6c6f.md)
- Last updated: 2020-08-02T07:35:46.603Z by yuki
- Full page listing (all children regardless of count): https://tips.weseek.co.jp/_api/v3/page-listing/children?id=5e424e61decd0a0049953ae1
