[React] useEffect, ||, &&

# 環境
MacBook Pro (2.3 GHz 8コアIntel Core i9)
macOS 14.0（23A344）
Homebrew 4.3.8
gh 2.52.0

# まとめ
> デフォルトの動作では、副作用関数はレンダーの完了時に毎回実行されます。

> 新しい購読を設定する必要があるのは毎回の更新ごとではなく、source プロパティが変化した場合のみです。

> useEffect の第 2 引数として、この副作用が依存している値の配列を渡します。

[条件付きで副作用を実行する](https://ja.legacy.reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect)

つまり、`useEffect`の依存配列（第二引数）を活用することで、`State`や`Props`が変更された場合にどの副作用（関数）を実行するかを細かく制御できます。

# 基本構文
`State`または`Props`として、`count`を設定した場合、`console.log("countが変更されたときに実行")`が副作用として実行される

~~~jsx:e.g.
useEffect(() => {
  console.log("countが変更されたときに実行");
}, [count]); // countが変更されたときのみ実行
~~~

# 活用例
## フォルダ構成
~~~:folda_structure
├── public/
│   ├── index.html
└── src/
│   ├── index.js(index.jsx)
│   └── App.js(App.jsx)
~~~

## index.html
~~~html:index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>React App</title>
  </head>

  <body>
    <div id="root"></div>
  </body>
</html>

~~~

## index.js
~~~jsx:index.js
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { App } from "./App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <StrictMode>
    <App />
  </StrictMode>
);
~~~

## App.js（useEffect**なし**）
- 課題：on/off`button`を使って、`＼(^o^)／ｵﾜﾀ`の表示・非表示が制御できない
- 考察：レンダリングの度に、`if`文に入るため、`onClickToggle`の制御が上書きされる

~~~jsx:App.jsx
import { useState } from "react";

export const App = () => {
  const [num, setNum] = useState(0);
  const onClickCountUp = () => {
    setNum(num + 1);
  };

  const [isShowFace, setIsShowFace] = useState(false);
  const onClickToggle = () => {
    setIsShowFace(!isShowFace);
  };

  if (num > 0) {
    if (num % 3 === 0) {
      isShowFace || setIsShowFace(true);
    } else {
      isShowFace && setIsShowFace(false);
    }
  }

  return (
    <>
      <button onclick={onClickCountUp}>カウントアップ</button>
      <p>{num}</p>
      <button onclick={onClickToggle}>on/off</button>
      {isShowFace && <p>＼(^o^)／ｵﾜﾀ</p>}
    </>
  );
};
~~~

## App.js（useEffect**あり**）
- 対策：`useEffect`を使用して、`num`が更新された時のみ`if`文が作動するように設定
- 結果：on/off`button`を使って、`＼(^o^)／ｵﾜﾀ`の表示・非表示が制御できる

~~~diff_jsx:App.jsx
import { useEffect, useState } from "react";

export const App = () => {
  const [num, setNum] = useState(0);
  const onClickCountUp = () => {
    setNum(num + 1);
  };

  const [isShowFace, setIsShowFace] = useState(false);
  const onClickToggle = () => {
    setIsShowFace(!isShowFace);
  };

+ useEffect(() => {
    if (num > 0) {
      if (num % 3 === 0) {
        isShowFace || setIsShowFace(true);
      } else {
        isShowFace && setIsShowFace(false);
      }
    }
+ }, [num]);

  return (
    <>
      <button onclick={onClickCountUp}>カウントアップ</button>
      <p>{num}</p>
      <button onclick={onClickToggle}>on/off</button>
      {isShowFace && <p>＼(^o^)／ｵﾜﾀ</p>}
    </>
  );
};
~~~~

## 処理の流れ
### カウントアップ`button`の操作(`useEffect`Hook**内**)
1. `num + 1`で、引数`num`を1つずつ増やす
1. `useState(true)`で、`isShowFace`の初期値を`false`に設定する
1. `||`で、引数(`state`)`isShowFace`が`false`の時に`setIsShowFace(true)`で`isShowFace`を`true`にする
1. `&&`で、引数(`state`)`isShowFace`が`true`の時に`setIsShowFace(false)`で`isShowFace`を`false`にする 
1. `&&`で、引数(`state`)`isShowFace`が`true`の時に`＼(^o^)／ｵﾜﾀ`が表示される

### on/off`button`の操作(`useEffect`Hook**外**)
1. `!isShowFace`で、引数`isShowFace`を反転させる
1. `&&`で、引数`isShowFace`が`true`の時に`＼(^o^)／ｵﾜﾀ`が表示される

## イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/3db4cec4-670b-5cc7-77c1-75340c7d3269.png)



# 参考リンク
- [state の管理](https://ja.react.dev/learn/managing-state)
- [コンポーネントの state](https://ja.legacy.reactjs.org/docs/faq-state.html)
- [論理和 (||)](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_OR)
- [論理積 (&&)](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_AND)
- [条件付きで副作用を実行する](https://ja.legacy.reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect)
- [モダンJavaScriptの基礎から始める挫折しないためのReact入門
](https://www.udemy.com/course/modern_javascipt_react_beginner)