質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

2回答

1945閲覧

Reactで生成したinputタグにonChangeイベントを追加したい!!

KobeanH

総合スコア6

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2022/01/22 03:28

Reactで生成したinputタグにonChangeイベントを追加したいです。

やりたいことは

1.「追加する」ボタンを押すとmoneyInputという変数のinputタグが生成

2.moneyInputタグに数字が入力されたらgetMoneyというstateに値が動的に格納される

という処理です。

上記の機能を実装するために以下のコードを書いたのですが、inputに入力した途端に入力した内容がconsoleに表示されるのではなく、入力後、適当なところをマウスでクリックするとconsoleに表示されます。

どうすれば入力直後にconsoleに表示されるようになりますか?

何卒、よろしくお願いします。

import { useState } from "react"; export const Game = () => { const [getMoney, setGetMoney] = useState(null); const getMoneyInput = (e) => { setGetMoney(() => e.target.value); }; const createInput = () => { let moneyInput = document.createElement("input"); moneyInput.setAttribute("type", "number"); moneyInput.setAttribute("placeholder", "金額を入力してください"); moneyInput.setAttribute("class", "moneyInput"); moneyInput.onchange = getMoneyInput; document.querySelector(".game").appendChild(moneyInput); }; console.log(getMoney); return ( <div className="game"> <button type="button" onClick={() => createInput()}> 追加する </button> </div> ); };

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2022/01/22 04:16 編集

React では普通 document.createElement は使いません。
KobeanH

2022/01/22 04:52

では、今回の場合どのように実装するのでしょうか?
maisumakun

2022/01/22 06:41

「追加する」とありますが、3回押せば3つ追加されるような動作が良いのでしょうか?
KobeanH

2022/01/22 09:29

その通りです。 しかし、実は今回質問させていただいたのはとある機能を実装するための一部分でして最終的には以下のような処理にしたいです。 1.「追加する」を押すと、inputタグが2つ生成される (1つ目は金額を入力するinputタグ、2つ目は人数を入力するinputタグ) 2.金額のinputタグに「1000」、人数のinputタグに「3」を入力すると、空の配列に「1000」を3つ格納する 例えば、 空の配列array1があるとします。 let array1 = []; 次に「追加する」を1回押したとします。 すると、金額を入力するinputタグと人数を入力するinputタグの2つを生成します。 次に金額inputに「1500」、人数inputタグに「2」を入力したとすると、array1の中身は let array1 = [1500, 1500]; となります。 続いて、もう一度、「追加する」ボタンを押したとします。 すると、別の金額を入力するinputタグと人数を入力するinputタグが生成されます。 そして、新しく生成された金額inputに「2500」、人数inputに「3」を入力すると、array1の中身は let array1 = [1500, 1500, 2500, 2500, 2500] になります。 以上のような機能を実装するにはどのようなコードが正しいのでしょうか? よろしくお願いします。
guest

回答2

0

ベストアンサー

質問への追記・修正依頼欄より

実は今回質問させていただいたのはとある機能を実装するための一部分でして最終的には以下のような処理にしたいです。

1.「追加する」を押すと、inputタグが2つ生成される
(1つ目は金額を入力するinputタグ、2つ目は人数を入力するinputタグ)

2.金額のinputタグに「1000」、人数のinputタグに「3」を入力すると、空の配列に「1000」を3つ格納する

例えば、

空の配列array1があるとします。

let array1 = [];

次に「追加する」を1回押したとします。

すると、金額を入力するinputタグと人数を入力するinputタグの2つを生成します。

次に金額inputに「1500」、人数inputタグに「2」を入力したとすると、array1の中身は

let array1 = [1500, 1500];

となります。

続いて、もう一度、「追加する」ボタンを押したとします。

すると、別の金額を入力するinputタグと人数を入力するinputタグが生成されます。

そして、新しく生成された金額inputに「2500」、人数inputに「3」を入力すると、array1の中身は

let array1 = [1500, 1500, 2500, 2500, 2500]

になります。

以上のような機能を実装するにはどのようなコードが正しいのでしょうか?

こんな感じでしょうか。

jsx

1import { useState } from 'react'; 2 3export const Game = () => { 4 const [items, setItems] = useState([]); 5 6 const createInput = () => { 7 setItems([...items, { amount: '', people: '' }]) 8 }; 9 10 const updateAmount = (index, value) => { 11 const newItems = [...items]; 12 newItems[index] = { ...items[index], amount: value }; 13 setItems(newItems) 14 }; 15 16 const updatePeople = (index, value) => { 17 const newItems = [...items]; 18 newItems[index] = { ...items[index], people: value }; 19 setItems(newItems) 20 }; 21 22 const array1 = []; 23 items.forEach(item => { 24 const amount = parseInt(item.amount) || 0; 25 const people = parseInt(item.people) || 0; 26 for (let i = 0; i < people; i++) { 27 array1.push(amount); 28 } 29 }); 30 31 return ( 32 <div className="game"> 33 <button type="button" onClick={createInput}> 34 追加する 35 </button> 36 {items.map((item, i) => ( 37 <div key={i}> 38 金額: <input type="number" value={item.amount} onChange={e => updateAmount(i, e.target.value)} /> 円、 39 人数: <input type="number" value={item.people} onChange={e => updatePeople(i, e.target.value)} />40 </div> 41 ))} 42 <p> 43 array1 = {JSON.stringify(array1)} 44 </p> 45 </div> 46 ); 47};

ポイントは、

  • React では入力欄の数だけ状態 (state) が必要です。入力欄の数が可変の場合は配列などを使いましょう。
  • 1 行の内容 (金額と人数) を一つのオブジェクト { amount: 金額, people: 人数 } として、その配列を用意します。
  • 配列の中身を書き換える場合、配列そのものと、値が変更されるオブジェクトは作り直す必要があります。
  • array1 は入力内容に基づいて計算できるので、毎回計算し直すと良いでしょう。

という感じで、普通の JavaScript とはまったく違う考え方をする必要があります。


コメント欄へのお返事

まず、... の意味はご存じでしょうか? これはスプレッド構文と言って、配列やオブジェクトの中身を取り出して、新しい配列やオブジェクトに埋め込む、という意味になります。
参考: JSのスプレッド構文を理解する - Qiita

例えば配列の場合、

js

1const a = [1, 2, 3]; 2const b = [...a, 4];

と書くと、...a の部分には a の中身が展開されて、b の値は [1, 2, 3, 4] になります。

配列の中身を書き換える場合、配列そのものと、値が変更されるオブジェクトは作り直す必要があります。

と書きましたが、例えば createInput を

js

1 const createInput = () => { 2 items.push({ amount: '', people: '' }); 3 setItems(items) 4 };

と書き換えると、追加ボタンを押しても何も起こらなくなります。これは、items の中身は書き変わったけど、items 自体は同じ配列なので、setItems しても値は変わってないとみなされてしまうためです。

同様に、updateAmount で const newItems = [...items]; としているのは、items 配列をコピーして setItems の時に新しい値として認識させるためです。

次の newItems[index] = { ...items[index], amount: value }; ですが、これはオブジェクトのスプレッド構文になります。例えば、

js

1const x = { a: 1, b: 2, c: 3 }; 2const y = { ...x, a: 4 };

とすると、...x の部分に x の中身が展開されるのは配列の場合と同様ですが、違うのは a というキーが重複していることですね。その場合、後ろに書いたものが優先されます。ので、y の値は { a: 1, b: 2, c: 3, a: 4 } ではなく、後ろの a: 4 が優先されて { a: 4, b: 2, c: 3 } になります。

今回の場合、items の各要素には amount と people しかないので、次のように書いても同じ結果になります。

js

1 newItems[index] = { amount: value, people: newItems[index].people };

が、スプレッド構文を使うと amount だけを書き換えたい、ということが明確になりますし、amount と people 以外に情報が増えても大丈夫です。

それから、array1 を計算する部分ですが、

js

1const amount = parseInt(item.amount) || 0; 2const people = parseInt(item.people) || 0;

実は item.amount や item.people は文字列になってます。これは、<input> の value に渡す時には文字列にしておかないと空欄にできないためですが、文字列なので例えば abc とか入力されたら parseInt の結果は NaN という、エラーを表す特別な値になります。これを確実に数値にする (エラーだったら 0 にする) ために || 0 を付けています。
参考: JavaScript parseInt, paeseFloat が NaN になるとき 0 を返したい - かもメモ

投稿2022/01/22 11:25

編集2022/01/22 14:55
hoshi-takanori

総合スコア7895

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KobeanH

2022/01/22 12:40

まさに、私がやりたいことが実現できました!! 本当にありがとうございます! もし、よければ const updateAmount = (index, value) => { const newItems = [...items]; newItems[index] = { ...items[index], amount: value }; setItems(newItems); }; const amount = parseInt(item.amount) || 0; const people = parseInt(item.people) || 0; updateAmountの一連の流れと amountとpeopleに【 || 0 】が書かれている理由を解説していただけないでしょうか? 調べても、いまいち理解できませんでした。
KobeanH

2022/01/22 13:03

追記です。 updateAmountに関してですが、 newItems[index] = { ...items[index], amount: value }; に...items{index}がなぜ必要なのかが、よくわかりませんでした。 ...items{index}を削除して動きを確認したら動き自体には特に問題ありませんでしたが、consoleを見ると、エラーが出ていました。 よろしくお願いします。
KobeanH

2022/01/23 03:27

めちゃくちゃわかりやすい解説ありがとうございます! ただ、もう二点気になったことがあり、 これは、<input> の value に渡す時には文字列にしておかないと空欄にできないためですが、文字列なので例えば abc とか入力されたら parseInt の結果は NaN という、エラーを表す特別な値になります。 とありますが、そもそもinputタグにvalue属性は必要なのでしょうか?value属性を削除しても特に動きに変わりはないので気になりました。 また、今回の場合、inputタグのtype属性がnumberなのでabcのような文字列は入力すらできない状態だと思うのですが、 const amount = parseInt(item.amount) || 0; この記述はあった方がいいよね、くらいの感覚でしょうか? ご教授いただけますと幸いです。
guest

0

react は仮想DOMを用いてるので、直接DOMをいじる(appendChildなど)よりは、仮想DOM上で完結させた方がよさそうです。

押したか押してないかの state (例えば、pressedAddButton)を用意し、それによって出すか出さないかを制御してみるのはどうでしょうか?

jsx

1// 省略 2{ 3 pressedAddButton && ( 4 <input ... /> 5 ) 6}

投稿2022/01/22 05:23

sum6

総合スコア232

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KobeanH

2022/01/22 05:50

ご回答ありがとうございます! 今回は「追加する」を押すたびにinputタグを生成し、そのinput全てにonChangeイベントを付与したいのですが、その場合、どのように実装するのでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問