2023.3.26
React.SetStateAction内でe.currentTargetがNULLになるのは仕様です
対象コード
次のシンプルなコンポーネントで確認します。
tsx_____sample.tsx_____import React from 'react';
export const SamplePage = () => {
const [myState, setMyState] = React.useState({
text: '',
num: 0,
});
return (
<>
<main className="flex justify-center items-center min-h-100vh rounded-12 p-30">
<div>
<p>
<>myState.text: {myState.text || 'Empty'}</>
</p>
<input
className={'mt-20 p-5 border-2 border-gray-200 rounded-4'}
onChange={(e) =>
setMyState((state) => {
return { ...state, text: e.currentTarget.value };
})
}
/>
</div>
</main>
</>
);
};
export default SamplePage;
生じる問題
上記のコンポーネントで、inputタグに文字を入力してみます。
e.currentTargetがnullだと怒られました。
これは e.currentTargetの仕様 通りの挙動です。
仕様には以下の記述があります。
メモ: イベント処理中だけ event.currentTarget の値は利用可能です。
もし console.log() で event オブジェクトを変数に格納し、コンソールで currentTarget キーを探すと、その値は null となります。
console.log(event.currentTarget) を使ってコンソールで表示するか、 debugger 文を使ってコードの実行を一時停止し、 event.currentTarget の値を表示させる必要があります。
今回のサンプルコードではonChangeのハンドラ内の処理ではありますが、React.SetStateActionという非同期処理内でe.currentTargetを参照しようとしたためすでにnullになっているというのが問題の原因でした。
修正
ということでイベント処理中にe.currentTargetからvalueを取り出しておけば良いということになります。
tsx_____sample.tsx_____import React from 'react';
export const SamplePage = () => {
const [myState, setMyState] = React.useState({
text: '',
num: 0,
});
return (
<>
<main className="flex justify-center items-center min-h-100vh rounded-12 p-30">
<div>
<p>
<>myState.text: {myState.text || 'Empty'}</>
</p>
<input
className={'mt-20 p-5 border-2 border-gray-200 rounded-4'}
onChange={(e) => {
const { value } = e.currentTarget; // <- 追加
setMyState((state) => {
return { ...state, text: value }; // <- 更新
});
}}
/>
</div>
</main>
</>
);
};
export default SamplePage;
まとめ
react-hook-formなどで非制御コンポーネントとして扱う場面も多いと思いますが、基本的な仕様の話なので記事にしておきました。