[React]①DogAPIを使ってuseState,useEffectを理解する[useState編]

## はじめに

本記事ではReactアプリケーションでDogAPIを叩きながら、useStateやuseEffectなどのReactの基本構文（ごく一部ですが）を知ることを目標としています。
今回はuseStateにフォーカスしています。

私自身もReact初学者のため、対象は初学者を想定しています。

## 開発環境
- node 21.2.0
- yarn 1.22.19

Reactの環境構築は[公式ドキュメント](https://ja.react.dev/learn/start-a-new-react-project)等を参考にしてください。

## Dog APIとは

世界中の犬の画像が利用できるAPIです。
今回はこのAPIを利用していきます。

https://dog.ceo/dog-api/

余談ですが、[リポジトリ](https://github.com/jigsawpieces/dog-api-images#dog-api-images)のPRで愛犬の画像を送ることもできるそうです。

## 犬の画像をランダムで一件ずつ取得してみる

ここから、Reactの環境構築が完了している前提で進めていきます。

まず、App.jsxに書き込んでいきましょう。
```App.jsx
import { useState } from 'react'

export const App = () => {
  const [dogUrl, setDogUrl] = useState(
    'https://images.dog.ceo/breeds/spaniel-brittany/n02101388_6057.jpg',
  )

  //return以下は省略

}

```

ここで`useState`が登場しました。このコードはいったん横に置いて、公式ドキュメントで紹介されているuseStateの基本的な使用例を紹介します。

```App.js
import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      You pressed me {count} times
    </button>
  );
}
```

ここで注目したいのが
```js
const [count, setCount] = useState(0);
```
の部分です。
箇条書きでまとめるとこんな感じです。

- `count`はstate変数の現在の値
- `setCount`はcountの値を操作するための関数
- `useState(0)`はcountの初期値を0に設定している
- 初回レンダー時（ページが呼び出された初回）にcountの値とuseState(0)の値が同じになります。

つまり、
```js
const [count, setCount] = useState(0);
```
の部分だけでわかることは、
countの値が（今は）0で、その値を操作するsetCount関数があるんだなということです。


続いて、`setCount関数`の使用例です。

```js
  function handleClick() {
    setCount(count + 1);
  }
```
ここではhandleClickという関数内で`setCount(count+1)`が定義されています。初期値が0のcountに対して、この関数が呼び出されるたびにcountの値が1ずつ増えるように更新されます。

最後にcountの状態を確認できるボタンを作ります。
```js
  return (
    <button onClick={handleClick}>
      You pressed me {count} times
    </button>
  );
```
onClickイベントで先ほど作った関数を呼び出しているので、ボタンを押すとhandleClick関数が呼び出され、`setCount(count+1)`が実行されます。

また、

```js
You pressed me {count} times
```
このコードではcountの最新の状態を確認できます。
例えば、
- ボタンを一度も押していない状態→初期値0が適用されるので`count=0`
- ボタンをn回押した状態→n回分値が+1されるので`count=n`

となります。
ここまでがuseStateの大まかな説明になります。

[公式ドキュメント](https://ja.react.dev/reference/react/useState)にさらに詳しい説明があるので余裕がある方は読んでみてください。

---

useStateについての説明がひと段落ついたので、一番はじめに紹介したこちらのコードを見ていきましょう。
```App.jsx
import { useState } from 'react'

export const App = () => {
  const [dogUrl, setDogUrl] = useState(
    'https://images.dog.ceo/breeds/spaniel-brittany/n02101388_6057.jpg',
  )

  //return以下は省略
}
```    
ここまでの説明を踏まえると
dogUrlの初期値が 'https://images.dog.ceo/breeds/spaniel-brittany/n02101388_6057.jpg'
というURLで、そのURLを操作するsetDogUrl関数が後続しそうだなということがわかると思います。

続いて、犬の画像をランダムで取得する処理を書いていきます。
(この辺りの書き方の理解が甘いのでベストプラクティスではないかもしれないです)
```js
  const changeDogImage = () => {
    fetch('https://dog.ceo/api/breeds/image/random')
      .then(res => res.json())
      .then(json => setDogUrl(json.message))
  }
```
DogAPIでは`'https://dog.ceo/api/breeds/image/random'`というURLが用意されており、これを操作することでランダムに画像を一件取得できます。
まず`fetch('https://dog.ceo/api/breeds/image/random')`のようにfetchの引数に取得したいリソースへのパスを書きます。
次に`.then(res => res.json())`でjsonデータを取得します。
最後に` .then(json => setDogUrl(json.message))` でsetDogUrl(json.message)で出力されるmessageをdogUrlに格納します。changeDogImage関数が呼び出されるたびに、dogUrlに格納される画像URLが更新される仕組みです。

DogAPIのJSONデータの呼び出し形式は[こちら](https://dog.ceo/dog-api/)から確認してください。messageをキーとしてURLが出力されます。

---

ここまでの説明を踏まえると現在のコードは以下のようになります。

```App.jsx
import { useState } from 'react'

export const App = () => {
  const [dogUrl, setDogUrl] = useState(
    'https://images.dog.ceo/breeds/spaniel-brittany/n02101388_6057.jpg',
  )

  const changeDogImage = () => {
    fetch('https://dog.ceo/api/breeds/image/random')
      .then(res => res.json())
      .then(json => setDogUrl(json.message))
  }

  return (
    <>
    </>
  )
}

export default App;
```

次に、changeDogImage関数を呼び出すボタンと取得した画像の表示場所を作ってみましょう。実装完了後は以下のようなコードになります。

```App.jsx
import { useState } from 'react'

export const App = () => {
  const [dogUrl, setDogUrl] = useState(
    'https://images.dog.ceo/breeds/spaniel-brittany/n02101388_6057.jpg',
  )

  const changeDogImage = () => {
    fetch('https://dog.ceo/api/breeds/image/random')
      .then(res => res.json())
      .then(json => setDogUrl(json.message))
  }

  return (
    <>
      <img src={dogUrl} alt="犬の画像"/>
      <button onClick={changeDogImage}>更新</button>
    </>
  )
}

export default App;
```

- `<img src={imageUrl} alt="犬の画像"/>`では、dogUrlをsrcにもつimgタグを作成しました。dogUrlの更新を受けて表示される画像も更新されます。
- `<button onClick={changeDogImage}>更新</button>`ではonClickイベントに先ほど作成したchangeDogImage関数を当てているので更新ボタンを押すたびにdogUrlの値が更新されます。

ここまで問題なく実装ができていると以下の状態になっていると思います。
更新ボタンを押すと画像がランダムで切り替わります。
![Videotogif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958845/cdc8da8f-704a-898e-cde2-e87f54736f70.gif)

今回はここまでになります。お疲れ様でした。
次回はuseEffectやコンポーネント分割、propsの使い方などにフォーカスを当てた記事を書きたいと思います。