From d1ea7417dc3b6c19edc9c8418022bb47b4c33d37 Mon Sep 17 00:00:00 2001 From: ken7253 Date: Thu, 21 Mar 2024 23:04:51 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=E3=81=96=E3=81=A3=E3=81=8F=E3=82=8A?= =?UTF-8?q?=E6=9B=B8=E3=81=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- articles/useeffect-with-event-handler.md | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 articles/useeffect-with-event-handler.md diff --git a/articles/useeffect-with-event-handler.md b/articles/useeffect-with-event-handler.md new file mode 100644 index 0000000..3db4e5b --- /dev/null +++ b/articles/useeffect-with-event-handler.md @@ -0,0 +1,49 @@ +--- +title: "「stateはスナップショットである」をバグから理解する" +emoji: "📌" +type: "tech" # tech: 技術記事 / idea: アイデア +topics: ["react"] +published: false +--- + +::: message +タイトルのキャッチーさのために「バグ」という言葉を利用してしまいましたが +ここで述べられているReactの挙動は正しいものでありタイトルで利用した「バグ」という表現は **「実装者が意図していなかった挙動」** のことを指します。 +::: + +まずはこのコードをご覧ください。 + +```tsx:Counter.tsx +import { useState, useEffect, type FC } from "react"; + +const Counter:FC = () => { + const [count, setCount] = useState(0); + + useEffect(() => { + const handler = (event: KeyboardEvent) => { + if (event.key === 'Enter') { + setCount(count + 1); + }; + console.log(count); + }; + + window.addEventListener('keydown', handler); + + return (() => window.removeEventListener('keydown', handler)); + }, []); + + return ( +
Counter
+ ) +}; +``` + +このコードでやってることを簡単にまとめると下記のようになります。 + +- `count`という`state`を定義 +- Enterキーが押下される度に`state`を+1するイベントハンドラーを定義 +- `useEffect`によってコンポーネントの初回レンダリング時にイベントハンドラーを設定 + +また、イベントハンドラー内にある`console.log()`では呼び出される度にログに`count`を出力します。 + +## state はスナップショットである From d208da6c99406386b63c58f0331e002113296421 Mon Sep 17 00:00:00 2001 From: ken7253 Date: Fri, 22 Mar 2024 00:52:39 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=E3=82=AF=E3=82=A4=E3=82=BA=E3=81=AE?= =?UTF-8?q?=E7=AD=94=E3=81=88=E3=82=92=E8=A8=98=E8=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- articles/useeffect-with-event-handler.md | 20 +++++++++++++++++- .../on-enter-console-log.png | Bin 0 -> 3486 bytes 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 images/articles/useeffect-with-event-handler/on-enter-console-log.png diff --git a/articles/useeffect-with-event-handler.md b/articles/useeffect-with-event-handler.md index 3db4e5b..f61bab1 100644 --- a/articles/useeffect-with-event-handler.md +++ b/articles/useeffect-with-event-handler.md @@ -11,6 +11,8 @@ published: false ここで述べられているReactの挙動は正しいものでありタイトルで利用した「バグ」という表現は **「実装者が意図していなかった挙動」** のことを指します。 ::: +## サンプルコードと問題 + まずはこのコードをご覧ください。 ```tsx:Counter.tsx @@ -44,6 +46,22 @@ const Counter:FC = () => { - Enterキーが押下される度に`state`を+1するイベントハンドラーを定義 - `useEffect`によってコンポーネントの初回レンダリング時にイベントハンドラーを設定 -また、イベントハンドラー内にある`console.log()`では呼び出される度にログに`count`を出力します。 +イベントハンドラー内にある`console.log()`では呼び出される度に`count`を出力します。 +コンポーネントが描画されている状態で`Enter`を3回押すとどのようなログになるでしょうか。 + +::: details 回答 +![Chrome開発者ツールのスクリーンショット、コンソールタブに3回0が出力されている](/images/articles/useeffect-with-event-handler/on-enter-console-log.png) +*`0`が3回出力されています。* + +今回のコードではこのように何度Enterを押してもコンソールには常に`0`が出力されます。 +::: + +実際に挙動を確認してみたい人は下記の埋め込みから確認できます。 + +@[codesandbox](https://codesandbox.io/embed/ly75kf?expanddevtools=1) ## state はスナップショットである + +Reactの公式ドキュメントにも記載があるように、stateは動的な変数というよりコンポーネントの呼び出し時には常に同じ値を指す定数のような扱いに近いです。 + +https://ja.react.dev/learn/state-as-a-snapshot diff --git a/images/articles/useeffect-with-event-handler/on-enter-console-log.png b/images/articles/useeffect-with-event-handler/on-enter-console-log.png new file mode 100644 index 0000000000000000000000000000000000000000..f52398f5446ef1834b48695d07117a2796d485ff GIT binary patch literal 3486 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 literal 0 HcmV?d00001