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

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

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

checkboxは、GUIのエレメントです。また、HTML<input>タグのtype属性で扱われる値を指します。

JavaScript

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

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

React.js

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

Q&A

解決済

1回答

6691閲覧

Reactで複数のチェックボックスのチェックされている状態とされていない状態をチェックボックス毎に管理したいです。

madaratyou

総合スコア7

checkbox

checkboxは、GUIのエレメントです。また、HTML<input>タグのtype属性で扱われる値を指します。

JavaScript

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

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

React.js

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

0グッド

1クリップ

投稿2020/12/24 15:14

前提・実現したいこと

Reactで複数のチェックボックスのチェックされている状態とされていない状態を管理したいです。
現状では、ischeckedという1つのstateで管理されており、どのチェックボックスをクリックしたかに関わらず、状態が変更してしまう状態です。
それをチェックボックス毎分離して管理したいと思っています。

この要件の次のステップとして、チェックをを入れるとそのチェックしたチェックボックスに応じてAPIを取得して、別のコンポーネントに渡すという要件があるため、親コンポーネントでstateを管理したいです。

該当のソースコード

  • App.jsx

JavaScript

1import React from "react"; 2import { CheckBoxes } from "./components/index"; 3 4export default class App extends React.Component { 5 constructor(props) { 6 super(props); 7 this.state = { 8 error: null, 9 isLoaded: false, 10 prefs: [], 11 isChecked: false, 12 }; 13 14 this.changeIsChecked = this.changeIsChecked.bind(this); 15 } 16 17 changeIsChecked = () => { 18 this.setState({ 19 isChecked: !this.state.isChecked 20 }) 21 console.log(this.state.isChecked) 22 } 23 24 componentDidMount() { 25 fetch("https://opendata.resas-portal.go.jp/api/v1/prefectures", { 26 headers: { 27 "X-API-KEY": "APIキーが入ります", 28 }, 29 }) 30 .then(res => res.json()) 31 .then( 32 (data) => { 33 this.setState({ 34 isLoaded: true, 35 prefs: data.result 36 }); 37 }, 38 (error) => { 39 this.setState({ 40 isLoaded: true, 41 error 42 }); 43 } 44 ) 45 } 46 47 render() { 48 const { error, isLoaded } = this.state; 49 if (error) { 50 return <div>Error: {error.message}</div>; 51 } else if (!isLoaded) { 52 return <div>Loading...</div>; 53 } else { 54 return ( 55 <CheckBoxes prefs={this.state.prefs} isChecked={this.state.isChecked} changeIsChecked={this.changeIsChecked} /> 56 ); 57 } 58 } 59} 60 61
  • CheckBoxes.jsx
import React from "react"; import { CheckBox } from "./index"; const CheckBoxes = (props) => { return ( <> {props.prefs.map((pref) => { return ( <CheckBox name={pref.prefName} key={pref.prefCode} isChecked={props.isChecked} changeIsChecked={props.changeIsChecked} /> ); })} </> ); }; export default CheckBoxes;
  • CheckBox.jsx
import React from "react"; const CheckBox = (props) => { return ( <> <label htmlFor='check'>{props.name}:</label> <input type='checkbox' id='check' isChecked={props.isChecked} onClick={() => props.changeIsChecked()} /> </> ); }; export default CheckBox;

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

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

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

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

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

guest

回答1

0

ベストアンサー

isChecked という一つの boolean (true/false) では一つのチェックボックスの状態しか管理できません。複数のチェックボックスの状態を管理するには、何らかの方法で各チェックボックスの状態を管理する必要があります。方法としては、配列的なもの(配列・連想配列・集合など)を使う方法と、各データそのものに isChecked 属性を勝手に追加してしまう方法があります。ここでは集合 (Set) を使ってみます。
JavaScript Setオブジェクト - Qiita
JavaScript | Setオブジェクト - Qiita

まず、isChecked の代わりに checkedCodes という集合を用意して、ここにチェックされた prefCode を格納することにします。

diff

1 export default class App extends React.Component { 2 constructor(props) { 3 super(props); 4 this.state = { 5 error: null, 6 isLoaded: false, 7 prefs: [], 8- isChecked: false, 9+ checkedCodes: new Set(), 10 }; 11 12 this.changeIsChecked = this.changeIsChecked.bind(this); 13 }

changeIsChecked には、どのチェックボックスが押されたかを区別するための引数 prefCode が必要です。
new Set(this.state.checkedCodes) は現在の checkedCodes をコピーしています。React では、集合などのオブジェクトを変更する場合には、必ずコピーしてから変更を加えて setState する必要があることに注意しましょう。
次の if 文は、checkedCodes に prefCode が含まれていればチェックされているということなので、prefCode を checkedCodes から取り除き、含まれてなければ追加します。
最後の console.log では、デバッグのために現在選択されている prefName をすべて表示しています。

diff

1- changeIsChecked = () => { 2- this.setState({ 3- isChecked: !this.state.isChecked 4- }) 5- console.log(this.state.isChecked) 6+ changeIsChecked = (prefCode) => { 7+ const checkedCodes = new Set(this.state.checkedCodes); 8+ if (checkedCodes.has(prefCode)) { 9+ checkedCodes.delete(prefCode); 10+ } else { 11+ checkedCodes.add(prefCode); 12+ } 13+ this.setState({ checkedCodes }); 14+ console.log(this.state.prefs.filter(pref => checkedCodes.has(pref.prefCode)).map(pref => pref.prefName)) 15 }

CheckBoxes にも isChecked の代わりに checkedCodes を渡します。

diff

1 render() { 2 const { error, isLoaded } = this.state; 3 if (error) { 4 return <div>Error: {error.message}</div>; 5 } else if (!isLoaded) { 6 return <div>Loading...</div>; 7 } else { 8 return ( 9- <CheckBoxes prefs={this.state.prefs} isChecked={this.state.isChecked} changeIsChecked={this.changeIsChecked} /> 10+ <CheckBoxes prefs={this.state.prefs} checkedCodes={this.state.checkedCodes} changeIsChecked={this.changeIsChecked} /> 11 ); 12 } 13 }

CheckBoxes では、各 CheckBoxes に渡す値のうち isChecked と changeIsChecked を変更します。
isChecked は checkedCodes に prefCode が含まれるかどうかでチェックされているかどうかを判定します。
また、changeIsChecked は prefCode を引数として呼び出すように変更します。

diff

1 const CheckBoxes = (props) => { 2 return ( 3 <> 4 {props.prefs.map((pref) => { 5 return ( 6 <CheckBox 7 name={pref.prefName} 8 key={pref.prefCode} 9- isChecked={props.isChecked} 10- changeIsChecked={props.changeIsChecked} 11+ isChecked={props.checkedCodes.has(pref.prefCode)} 12+ changeIsChecked={() => props.changeIsChecked(pref.prefCode)} 13 /> 14 ); 15 })} 16 </> 17 ); 18 };

CheckBox は変更の必要はないはずですが、input タグの属性としては checked や onChange の方が正しそうなので修正しました。また、br タグは個人的に改行した方が見やすかったので。

diff

1 const CheckBox = (props) => { 2 return ( 3 <> 4 <label htmlFor='check'>{props.name}:</label> 5- <input type='checkbox' id='check' isChecked={props.isChecked} onClick={() => props.changeIsChecked()} /> 6+ <input type='checkbox' id='check' checked={props.isChecked} onChange={() => props.changeIsChecked()} /> 7+ <br /> 8 </> 9 ); 10 };

投稿2020/12/25 05:51

hoshi-takanori

総合スコア7901

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

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

madaratyou

2020/12/26 12:53

的確な回答ありがとうございます。 <label>をクリックしたときにもチェックのつけ外しをできるようにしたかったので、 onClick={() => props.changeIsChecked()} を<label>に追加したのですが、<label>をクリックするとなぜかクリックしたprefCodeと同時に1が同時に取得されているみたいでどの<label>をクリックしてもprefCode=1のチェックボックスにチェックが付いたり、外れたりしてしまいます。 これの解決策を教えていただけると幸いです。
hoshi-takanori

2020/12/26 13:29

label にはもともと htmlFor 属性がついてますが、これは html 的には for 属性になります。 https://qiita.com/nogizaka46/items/612ba6522d546f5f954f#htmlfor で、label に for がついていると、その id の input タグが押されたことになるのですが、html 的には id は一つのページの中でユニークである必要があります。ところが、CheckBox.jsx では htmFor にすべて同じ check が指定されているために、最初に見つかった id='check' の input 要素が押されたことになってるんだと思います。 https://teratail.com/questions/55463 解決方法としては、CheckBox の props に prefCode を渡して htmlFor および input の id に prefCode をつけるか (その場合は label の onClick は不要なはず)、いっそのこと htmlFor を削除して label の onClick だけで処理するか、でしょうか。
hoshi-takanori

2020/12/26 13:59 編集

もう一つ方法がありました。label 要素は input 要素を囲む形で使うことができ、この場合は htmlFor も onClick も input の id も不要になるので、これが一番簡単かもしれません。(古いブラウザは対応してなかったような気もしますが、もう 2020 年も終わるし気にしなくていいはず…。) あと、CheckBox.js では changeIsChecked に引数を渡す必要がないので、onChange も簡単に書けるはず。 <label>{props.name}: <input type='checkbox' checked={props.isChecked} onChange={props.changeIsChecked} /> </label> 参考 https://teratail.com/questions/142872
madaratyou

2020/12/26 14:36

ありがとうございます。2つ目の方法でできました。!! 本当にお世話になります。!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問