フロントエンドを触る上でデザイナーが知っとくと便利なjs知識〜3. クラスコンポーネント(クラス・メソッド・state)を理解する〜

※現職を退職するにあたって、2020年に社内ナレッジ置き場で書いたものを転載していますので、クラスコンポーネント前提だったりと古い情報が含まれます。機会があれば随時修正します。

親記事

https://qiita.com/setsumaru1992/items/f9263eeab5c651471fca

# 値の型
1,2,3を「数値」というのは納得だと思います。
プログラミングでは1,2,3のようなものを「値」、値の種類を「型」と言います。

| 型 | 型の意訳 | 値例 |
| --- | --- | --- |
| number | 数値（整数） | 1,2 |
| float | 小数 | 0.5, 1.2 |
| string | 文字列。引用符がついているもの<br>jsでは慣例で`''` | a", '1', 'あ'|
| boolean | 真偽値。簡単に言うとon,offの2値 | true / false のみ true=on,真、false=off,偽 |
| array | リスト。`[]`でくくる | [9,8,7] [''あ,''apple,'33'] |
| object | オブジェクト、マップ。{属性名: 値}の形 | {name: 'tanaka', age: 23} |
| any | 全部の値入れていい型。裏技（多用厳禁） | 1,'a',true |




# 関数とは
乱暴に言うと、材料に、処理をして、いい感じの結果を出すものです。
```js
function add(num1, num2){
  return num1 + num2;
}

add(3, 5) // →8
add(add(3,5), 5) // →13
```
`num1`, `num2`のような材料のことを「引数」と呼び
`num1 + num2`のようないい感じの結果のことを「返り値」と呼び、`return`の直後にその関数で返したい結果を書きます。
なお、引数と返り値は必須でなく、関数によって必要なら設定するという感じです。

ちなみに、関数の後ろに`(引数)`を付けた場合は処理をした結果を返してくれるんですが、`()`がない場合、結果ではなく、関数自体を返します。
（後でこの話が出てくるのでそのときになってから戻ってきても良いかもしれません。）

```js
const sampleVariable = add(3,5) // sampleVariableには8という数字が入る
const sampleFunc = add // sampleFuncにはaddという関数が入る
```

# クラスとは
この説明でわからないことを承知で一文でいうと、「属性（別名：フィールド）」と「振舞い（属性に伴う動作、行動、関数　別名：メソッド）」を持つものです。
クラス自体は属性と振舞いの設計図であり、設計図を元に作った実体や具体例を「インスタンス」と言います。（Reactではインスタンスはあまり気にしなくてよく、クラスだけ考えればいいです）

例を元にしないと理解しにくいと思うので、以下のコードを例に説明します。

```ts
class Person{
  constructor(name, age){
    this.name = name;
    this.age = age;
  }
  
  sayName(){
    window.alert(this.name);
  }

  sayAge(){
    window.alert(this.age);
  }
  
  getProfile(){
    return '私の名前は' + this.name + 'で、' + this.age + '歳です'
  }
}

const tanaka = new Person('tana~ka', 23)
tanaka.sayName(); // アラートで'tana~ka'が表示される
tanaka.getProfile(); // 私の名前はtana~kaで、23歳です
```

名前(`name`)と年齢(`age`)という属性（フィールド）を持ち、
`sayName`と`sayAge`という振舞い（メソッド）を行うことができる
`Person`というクラスがあり、
そのクラス（設計図）を元に`tana~ka`という名前で、23歳の`tanaka`というインスタンス（実体）を作り 、
`tanaka`が`sayName`を実行しています

## 継承
あるクラスを作るときに、既存のクラスを元にしてクラスを作ることができます。
```ts
class Bimajo extends Person{
  constructor(name, age, wakadukuriAge){
    super(name, age);
    this.wakadukuriAge = wakadukuriAge;
  }

  sayYoungAge(){
    window.alert(this.age - this.wakadukuriAge);
  }
}

const hiroko = new Person('hiroko', 58, 20)
hiroko.sayName(); // アラートで'hiroko'が表示される(Personのメソッドが使える)
hiroko.sayYoungAge(); // アラートで'38'が表示される(Bimajoのメソッドが使える)
```


# クラスコンポーネントとは
コンポーネントとはjsxを作るものです。
他のesaにも書いてあるとおり関数コンポーネントとクラスコンポーネントというものがあり、関数コンポーネントはその関数の返り値にjsxを書き、クラスコンポーネントは`render`メソッドの返り値にjsxを書きます。

クラスコンポーネントとは「クラス」であり「コンポーネント」です。
つまり「属性（フィールド）と振舞（メソッド）を持てる」「jsxを作るもの」です。
（属性も振舞も持たない場合クラスコンポーネントである必要がないので関数コンポーネントで作ります。）

以下では可視性をコントロールする`visible`という属性を持ち、その切替を行う`toggleVisiblity`という振舞（メソッド）を持ったクラスコンポーネントについて説明します

```Menu.tsx
class Menu extends React.Component<Props, State> { // L1
  constructor(props: Props, state: State){ // L2
    super(props, state); // L3
    this.state = {visible: false}; // L4
    bindAll(this, ['closeMenu', 'toggleVisiblity']); // L5
  }

  closeMenu(){ // L6
    this.setState({visible: false}); // L7
  }

  toggleVisiblity(){ // L8
    const { visible } = this.state; // L9
    this.setState({visible: !visible }); // L10
  }

  render(){ // L11
    const { visible } = this.state; // L12
    return ( // L13
      <div> {/* L14 */}
        <div onClick={this.toggleVisiblity}> {/* L15 */}
          {visible ? '閉じる' : '開く'} {/* L16 */}
        </div> {/* ↓L17 */}
        {visible && (
          <div> {/* L18 */}
            <CloseButton onClick={this.closeMenu} /> {/* L19 */}
            <ul>
              <li>トップページ</li>
              <li>マイページ</li>
              <li>ログアウト</li>
            </ul>
          </div>
        )}
      </div>
    )
  }
}
```

```CloseButton.jsx
interface Props { // L1
  onClick: any; // L2
}

function CloseButton(props: Props){ // L3
  const { onClick } = props; // L4
  // ↓L5
  return (
    <div onClick={onClick}>
      × {/* L6 */}
    </div>
  )
}
```

## state(react内で管理する属性・フィールド)
reactのクラスコンポーネントで扱うフィールドは`state`と言い、特別な管理（参照・更新）方法を使います。

### stateの初期化
```Menu.tsx
  constructor(props: Props, state: State){ // L2
    ...
    this.state = {visible: false}; // L4
```
`constructor`メソッドの中の`this.state = {~: ~}`のところで、stateの初期値を設定します。
上記例だと、`visible`というフィールドの初期値、つまり変更しない状態での最初の値を`false`に設定しました。
つまりメニューが最初は見えない状態です。

### stateによる表示や出し分け

```Menu.tsx
    const { visible } = this.state; // L12
    return ( // L13
      ...
          {visible ? '閉じる' : '開く'} {/* L16 */}
        </div> {/* ↓L17 */}
        {visible && (
          <div> {/* L18 */}
```
L12でstateの`visible`を取り出しています。stateを取り出すときはこのように書くと覚えてください。
※元の形は`const visible = this.state.visible`とstateの中の`visible`を`const visible`という変数に入れるという書き方なんですが、それを楽にしたのがL12の書き方でReact触る人はこの書き方を好んでます（好む理由は1行で複数のstateやpropsを取得できるからです）

L13以下で書くjsx内で取り出した`visible`を使います。

L16では三項演算子を使い、`visible`の値によって表記を変えています。
`visible`が`true`、つまりメニューが見えている・開いているときは「閉じる」
`visible`が`false`、つまりメニューが見えていない・閉じているときは「開く」
が表示されます。

L17はメニューの出し分けを行っています。
`{visible && (`の書き方は`visible`がtrueの場合にだけ
`&&`以降を表示する = L18以降のメニューを表示する
ということを表しています。


## メソッド
### 定義方法
```Menu.tsx
  closeMenu(){ // L6
    this.setState({visible: false}); // L7
  }

  toggleVisiblity(){ // L8
    const { visible } = this.state; // L9
    this.setState({visible: !visible }); // L10
  }
```
`constructor`と同じようなインデントでクラスのメソッドを定義していきます。

L6の`closeMenu`はメニューを閉じるメソッドです。やっていることはvisibleをfalseにするだけです。
stateのセットは`this.setState(更新したいstateのフィールドと値のオブジェクト)`で行います。

L8の`toggleVisiblity`は可視性を切り替えます。反転させます。trueだったらfalse(開く→閉じる)に、falseだったらtrue(閉じる→開く)に。
コードの説明をします。
L9で現在のvisibleの値をstateから取り出しています。
L10でvisibleを反転させてstateにセットしています。`!`をbooleanの前につけると反転します。

```Menu.tsx
import bindAll from 'pixta-ui';
  ...
  constructor(props: Props, state: State){ // L2
    ...
    bindAll(this, ['closeMenu', 'toggleVisiblity']); // L5
```
一応これを書かなきゃ動かないというおまじないがあります。理由は複雑なので割愛します。
`constructor`の中で`bindAll(this, ['メソッド名', 'メソッド名']); `と書きます。

### 使い方
```tsx
        <div onClick={this.toggleVisiblity}> {/* L15 */}
```
jsxで使う場合は`this.メソッド名`の形でメソッドを使います。
大抵onClickだと思うんですが、そういう`on~`系のHTML属性には関数しか渡せません。なので、`()`なしの関数を渡します。
※冗長に書けば`(e) => {this.メソッド名(e)}`とかになりますが、それを簡略化したものが↑の書き方です。

## props - 他のコンポーネントに値を引き渡す
railsのパーシャル的にjsxの中に他のコンポーネントを入れることができます。
前述の`Menu`コンポーネントのようにそのコンポーネントだけで完結するコンポーネントもありますが、
時には`Menu.tsx`が`CloseButton.tsx`をパーシャル的に使っているときのように、
パーシャルとして使われている側（CloseButton）が使っている側（Menu）の値を流用しているときがあります。

### propsを使う
```CloseButton.jsx
interface Props { // L1
  onClick: any; // L2
}

function CloseButton(props: Props){ // L3
  const { onClick } = props; // L4
  // ↓L5
  return (
    <div onClick={onClick}>
      × {/* L6 */}
    </div>
  )
}
```
L3はpropsを使うという宣言で、
L4はstateと同様propsから値を取得しています（`const onClick = props.onClick`と同様です）。
L6で`div`の`onClick`属性にpropsから取ってきた関数を入れている


### propsに値を渡す
```Menu.tsx
            <CloseButton onClick={this.closeMenu} /> {/* L19 */}
```
propsとして利用する値を、パーシャルとして使う側がコンポーネントを呼ぶときに設定します。
今回は`CloseButton`で使うpropsの`onClick`に値を詰めています。
コンポーネントに使う`onClick`とかはpropsに値を渡すことしかできなくて、
HTML要素の属性のような`className`とか`style`とかは定義できません。

（紛らわしくて申し訳ないんですが、`<CloseButton onClick={this.closeMenu} />`のonClickはHTML属性のonClickではなく、propsとして渡すonClickという属性です。
なぜ例で紛らわしく書いているかというと、デザイナーさんがpropsやstateについて関心を持つときって可視性切り替えのときくらいだと思っており、そのときはonClickという属性を付けたほうがエンジニアの考えっぽいからです
なぜエンジニアの考えっぽいかと言うと、CloseButtonなど汎用的なエンジニアロジックではなく見た目重視のコンポーネントを作ったときには、コンポーネントではなくあたかもHTMLタグのように見えるほうがスマートなため、HTML属性と同じ名前を付けているからです）