【React】カウンターAppでuseState, useEffectを使ってみた


## はじめに
React Hooks(useState, useEffect)の使い方をカウンターAppでデモしながらご紹介します。

## useStateとuseEffectとは
### useState
useStateは関数コンポーネントにstateを持たせることができ、コードは下記の通りです。

```tsx
const [state, setState] = useState(initialState);
```
第一引数: `現在のstate`
第二引数: `stateを更新するための関数(呼び出し用の関数)`

`state`, `setState`, `initialState`は任意の名前を付けられます。

useStateは現在の state と、それを更新するための関数を、ペアにして返します。
なので分割代入をしています。

例えば`state`に1を追加したい場合は、`setState(state+1)`で実行できます。


### useEffect
useEffectは副作用を実行することができ、基本の形は下記のとおりです。

```tsx
useEffect(() => {
    effect
    return () => {
      cleanup
    }
  }, [input])
```

機能としては第二引数(`[input]`)に変更があった場合に第一引数(関数部分)を実行することというものです。第二引数は配列[]で指定します。

第二引数が空配列[]の場合、初回レンダリングのみ関数が呼ばれます。
また第二引数が省略された場合、レンダリングした際に毎回関数が呼ばれます。

## Appを作成

```:ターミナル
$ npx create-react-app count-app --typescript               
```

まず、useStateを用いてCounterAppを作成します。

```App.tsx
import React, { useState } from 'react';

function CountApp() {
  
  const[ count, setCount ] = useState(0);

  return(
    <>
      <h1>Counter App</h1>
      <h2>{count}</h2>
      <button onClick={()=> setCount(count+1)}>+ number1</button>
    </>
  );
}

export default CountApp;
```
![useState.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497683/d8f75af8-ffca-d624-6670-4add0c2ae81c.gif)


次にuseEffectでconsoleにログを出してみます。

```App.tsx
import React, { useState, useEffect } from 'react';

function CountApp() {
  const[ count, setCount ] = useState(0);

  useEffect(() => {
    console.log("Add number1")
  }, [count])

  return(
    <>
      <h1>Counter App</h1>
      <h2>Count: {count}</h2>
      <button onClick={()=> setCount(count+1)}>+ number1</button>
    </>
  );
}

export default CountApp;
```


useEffectの部分を正式なフォーマットに倣うと下記のコードになります。
今回はログを出すだけなので、宣言せずにそのまま使用しました。

```tsx
useEffect(() => {
    const log = () => {console.log("add")};
    return () => {
      log();
    };
  }, [count])
```


![useEffect.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497683/007ba19c-e263-505c-3e04-de7782631c6c.gif)


## useStateとuseEffectは複数使用可能

```App.tsx
import React, { useState, useEffect } from 'react';

function CountApp() {
  const[ count, setCount ] = useState(0);
  const[ count2, setCount2 ] = useState(0);


  useEffect(() => {
    console.log("Add count")
  }, [count])

  useEffect(() => {
    console.log("Add count2")
  }, [count2])

  return(
    <>
      <h1>Counter</h1>
      <h2>count: {count}</h2>
      <button onClick={()=> setCount(count+1)}>+ number1</button>
      <h2>count2: {count2}</h2>
      <button onClick={()=> setCount2(count2+1)}>+ number2</button>
    </>
  );
}

export default CountApp;
```
![counter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497683/9bb93cd8-e354-65c7-87dd-155ac16f72c1.gif)


## 番外編
### 初期値の切り出し
Typescriptっぽく初期値を切り出してみました。

```App.tsx
import React, { useState, useEffect } from 'react';

interface Props {
  initialCount: number;
}

function CountApp({initialCount}: Props) {
  const[ count, setCount ] = useState(initialCount);

  useEffect(() => {
    console.log("Add")
  }, [count])

  return(
    <>
      <h1>Hooks</h1>
      <h2>Count: {count}</h2>
      <button onClick={()=> setCount(count+1)}>+</button>
    </>
  );
}

export default CountApp;
```

### 関数の切り出し
setCountをreturnの外で定義してみました。

```App.tsx
import React, { useState, useEffect } from 'react';

function CountApp() {
  const[ count, setCount ] = useState(0);

  const addCount1 = () => {
    setCount(count + 1);
  }

  useEffect(() => {
    console.log("Add number1")
  }, [count])

  return(
    <>
      <h1>Couner App</h1>
      <h2>number1: {count}</h2>
      <button onClick={addCount1}>+</button>
    </>
  );
}

export default CountApp;
```

## 終わりに
かなり初歩的な使い方ですが、useStateとuseEffectの使い方をデモしてみました。