【React入門】学習メモ #3

この記事は[React Advent Calendar 2020](https://qiita.com/advent-calendar/2020/react) 18日目の記事です。

前回までの記事です。

[【React入門】学習メモ #1](https://qiita.com/masa99_it/items/3c27f04045bb7b675425)
[【React入門】学習メモ #2](https://qiita.com/masa99_it/items/ebb8dafc9c49a7c89fd8)


# はじめに

React学習の備忘録です。
間違い等ございましたら、ご指摘いただけますと幸いです

今回は、実際にサンプルを作りながらReactにおける**表示/非表示**の考え方を学習していきます。成果物としては、**ボタンによる切り替えプログラム**です。

## 成果物

[![Image from Gyazo](https://i.gyazo.com/b308a9d55c18cad1308e66b4b2fd507f.gif)](https://gyazo.com/b308a9d55c18cad1308e66b4b2fd507f)

## 環境構築

### プロジェクトの作成

```
$ npx create-react-app プロジェクト名
```

プロジェクト名は何でもOKです。

### ディレクトリ構造と使用ファイル

ディレクトリ構造

```
プロジェクト/
 ├─ src/
   ├─ index.js
   └─ component/
      ├─ Button.jsx
      └─ Button.css
```

使用するファイル

```
- index.js
- Button.jsx
- Button.css
```

### index.jsの変更点

ReactDOM.renderを弄って、表示させるコンポーネントを変更します

```index.js
import Button from './component/Button';  //Buttonをimport

ReactDOM.render(
  <React.StrictMode>
    <Button />  {/* App -> Button に変更してください */}
  </React.StrictMode>,
  document.getElementById('root')
);
```

これで下準備は終了です。

## 表示/非表示の考え方

考え方は至ってシンプルです。
`state`を使い、`state`の切り替えによって**表示/非表示**を実現します。

使用するのは以下2点

- state
- if文

## 実装の順序

1. 格stateの定義
2. stateを変更するメソッドを定義
3. JSXとif文を組み合わせて格部品を作成
4. 部品の表示

### 1.格stateの定義

clickボタンを押下して出現する文字列は初期状態では表示させなくてもよいので、`false`です。
clickボタンは初期状態で表示させたいので、`true`です。

```Button.jsx
constructor(props) {
  super(props);
  this.state = {
    // 文字列の状態
    isOpenStr: false,
    // clickボタンの状態
    isOpenButton: true
  };
}
```

### 2.stateを変更するメソッドを定義

```Button.jsx
// clickボタンを押下したときに呼び出す
handleClickOpen() {
  // 文字列を表示
  this.setState({isOpenStr: true});
  // clickボタンを非表示
  this.setState({isOpenButton: false});
}

// とじるボタンを押下したときに呼び出す
handleClickClose() {
  // 文字列を非表示
  this.setState({isOpenStr: false});
  // clickボタンを表示
  this.setState({isOpenButton: true});
}
```

コメントの通りです。

### 3.JSXとif文を組み合わせて格部品を作成



```Button.jsx
render() {
    // 文字列を格納する変数
    let str;
    // isOpenがtrue（clickボタンが押されたとき）の状態
    if (this.state.isOpenStr) {
      str = (
        <div>
          <h1>Hello React</h1>
          {/* とじるボタン（とじるボタンを押下するとhandleClickCloseメソッドによりisOpenがfalseに切り替わり要素が消える） */}
          <button className='close-btn' onClick={() => {this.handleClickClose()}}>とじる</button>
        </div>
      );
    }

    // ボタンを格納する変数
    let btn;
    // isOpenButtonがtrue（clickボタンがまだ押下されていないとき）の状態
    if (this.state.isOpenButton) {
      btn = (
        <div>
          {/* 表示ボタン（clickボタンを押下するとhandleClickOpenメソッドにより、isOpenがtrueに切り替わり要素が出現する） */}
           <button onClick={() => {this.handleClickOpen()}}>Click</button>
        </div>
      );
    }
```

それぞれのif文の条件を解説すると、

**(this.state.isOpenStr)**がtrueであれば、中の処理を実行する。
trueというのは、clickボタンを押下した状態のことです。（clickボタンを押下しなければtrueにはなりません）

**(this.state.isOpenButton)**がtrueであれば、中の処理を実行する。
trueの状態は、初期状態なのでclickボタンが押されていない状態になります。

<br />

中の処理に関して解説すると、

1. clickボタンを押下で**handleClickOpen**メソッドが実行
2. **handleClickOpen**メソッドによって、stateが変更される
3. その結果、clickボタンは非表示になり、文字列と、とじるボタンが表示されます
4. とじるボタンを押下で**handleClickClose**メソッドが実行
5. **handleClickClose**メソッドによって、stateが変更される
6. その結果、clickボタンが表示され、文字列と、とじるボタンが非表示になります

### 4.部品の表示

最後にreturnの中で`中括弧{}`を用いてそれぞれの部品を表示しています。

```Button.jsx
return(
    <div>
      { str }
      { btn }
    </div>
  );
```

## 成果物

最終的な成果物になります。
コピペで直ぐに動きますので、是非ご自身のローカル環境で動かしてみてください。

```Button.jsx
import React from 'react';
import './Button.css';

class Button extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      // 文字列の状態
      isOpenStr: false,
      // clickボタンの状態
      isOpenButton: true
    };
  }

  // clickボタンを押下したときに呼び出す
  handleClickOpen() {
    // 文字列を表示
    this.setState({isOpenStr: true});
    // clickボタンを非表示
    this.setState({isOpenButton: false});
  }

  // とじるボタンを押下したときに呼び出す
  handleClickClose() {
    // 文字列を非表示
    this.setState({isOpenStr: false});
    // clickボタンを表示
    this.setState({isOpenButton: true});
  }

  render() {
    // 文字列を格納する変数
    let str;
    // isOpenがtrue（clickボタンが押されたとき）の状態
    if (this.state.isOpenStr) {
      str = (
        <div>
          <h1>Hello React</h1>
          {/* とじるボタン（とじるボタンを押下するとhandleClickCloseメソッドによりisOpenがfalseに切り替わり要素が消える） */}
          <button className='close-btn' onClick={() => {this.handleClickClose()}}>とじる</button>
        </div>
      );
    }

    // ボタンを格納する変数
    let btn;
    // isOpenButtonがtrue（clickボタンがまだ押下されていないとき）の状態
    if (this.state.isOpenButton) {
      btn = (
        <div>
          {/* 表示ボタン（clickボタンを押下するとhandleClickOpenメソッドにより、isOpenがtrueに切り替わり要素が出現する） */}
           <button onClick={() => {this.handleClickOpen()}}>Click</button>
        </div>
      );
    }

    return(
      <div>
        { str }
        { btn }
      </div>
    );
  }
}

export default Button;
```

```Button.css
body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
  text-align: center;
  min-width: 400px;
}

#root {
  margin-top: 15%;
}

.close-btn {
  font-size: 13px;
  color: #8491a5;
  width: 200px;
  padding: 16px 0;
  border: 0;
  background-color: #f0f4f9;
  cursor: pointer;
}

h1 {
  font-size: 64px;
  margin: 0 auto;
}

button {
  display: inline-block;
  font-size: 32px;
  width: 200px;
  height: 48px;
  border-radius: 4px;
  margin-right: 24px;
  margin-left: 24px;
  color: #fff;
  background-color: #66ccff;
  border: none;
  outline: none;
  box-shadow: 4px 4px #d8d8d8;
  cursor: pointer;
  appearance: none;
}

button:active {
  position: relative;
  top: 4px;
  left: 4px;
  box-shadow: none;
}
```

終わり。