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

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

新規登録して質問してみよう
ただいま回答率
85.50%
React.js

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

Q&A

解決済

1回答

4823閲覧

Reactで選択したアイテムを追加/削除できるようにしたい

k10a

総合スコア35

React.js

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

0グッド

0クリップ

投稿2018/07/10 15:49

前提・実現したいこと

Reactで複数のアイテムを追加したり、削除するサンプルを実現したいです。
例)一つ目のアイテムを追加してクリックした後、もう一度同じアイテムをクリックするとそのアイテムは選ばれなくなる。別のアイテムをクリックすると、既にクリックされているアイテムに続いて追加される。

発生している問題・エラーメッセージ

{items: Array(2), count: 0, selectedItems: Array(1)} count: 0 items: Array(2) 0: {id: 1, name: "React", chosen: true} 1: {id: 2, name: "Redux", chosen: false} length: 2 __proto__: Array(0) selectedItems: Array(2) 0: {id: 1, name: "React", chosen: false, setItemStatus: ƒ} 1: {id: 2, name: "Redux", chosen: false, setItemStatus: ƒ} 2: {id: 2, name: "Redux", chosen: true, setItemStatus: ƒ} length: 3__proto__: Array(0)__proto__: Object

これは両方のアイテムをクリックした後に、2つめのアイテムをもう一回クリックしていますが、また追加されてしまっているみたいです。また、chosenのステータスも逆になっています。

該当のソースコード

◾️Select.js
親コンポーネント

import React, { Component } from 'react'; import ItemList from './common/ItemList'; class Select extends Component { constructor(props) { super(props); this.state = { items: [ { id: 1, name: 'React', chosen: false, }, { id: 2, name: 'Redux', chosen: false, } ], count: 0, // カウント数の状態を追加 selectedItems: [] // 追加したアイテムの情報を追加 }; } onChoose() { this.setState({ count: this.state.count + (this.state.chosen ? -1 : 1), chosen: false }); } setItemStatus(clickItem) { // 該当のitemを取り出す const items = this.state.items.slice(); const item = items[clickItem.id - 1]; // itemの状態を変更 item.chosen = !item.chosen; console.log('this', this.state); console.log('ggggg', clickItem); // selectedItemにclickItemを追加(もしくは排除) const selectedItems = this.state.selectedItems; if( selectedItems.indexOf(clickItem) >= 0) { selectedItems.remove(clickItem) } else { selectedItems.push(clickItem) } this.setState({ items, selectedItems }); } render() { return ( <div className="App"> <h1>SelectItem</h1> <ItemList items={this.state.items} setItemStatus={this.setItemStatus.bind(this)} /> </div> ); } } export default Select;

◾️ItemList.js
中間コンポーネント

JavaScript

1import React, { Component } from 'react'; 2import Item from './Item'; 3 4class ItemList extends Component { 5 6 render() { 7 const items = this.props.items.map( item => 8 <Item 9 key={item.id} 10 {...item} 11 setItemStatus={this.props.setItemStatus} 12 /> 13 ) 14 15 return( 16 <ul> 17 {items} 18 </ul> 19 ); 20 } 21} 22 23export default ItemList

◾️Item.js
子コンポネーント

JavaScript

1import React, { Component } from 'react'; 2 3class Item extends Component { 4 render() { 5 6 const link = this.props.chosen ? 'unselected' : 'selected' 7 return ( 8 <button onClick={this.props.parentMethod}> 9 <span>{this.props.id}</span> 10 <span>{this.props.name}</span> 11 <a href="" onClick={(e) => { 12 e.preventDefault(); 13 this.props.setItemStatus(this.props) 14 }}>{link}</a> 15 </button> 16 ); 17 } 18} 19 20export default Item

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

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

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

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

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

guest

回答1

0

ベストアンサー

以下の select コンポーネント中に出てくる selectedItems.remove() ってなんですか?
selectedItems はただの Array オブジェクトだと思うんですが、.remove() メソッドは初めて見ました。

js

1// select class 2setItemStatus(clickItem) { 3 ... 4 if( selectedItems.indexOf(clickItem) >= 0) { 5 selectedItems.remove(clickItem) // <- これ 6 } else { 7 selectedItems.push(clickItem) 8 } 9 ... 10}

アイテムが選択されたことを表す chosen プロパティと selectedItems が state にいますが、役割被ってて冗長に感じますね。
選択されたアイテム数を表す count も冗長ですね。

state の count と selectedItems は提示のコードを見る限り使われていないので除去して構わないと想います。必要になれば以下の方法で取れるので。

js

1selectedItems = this.state.items.filter(item => item.chosen); 2count = this.state.items.filter(item => item.chosen).length + 1;

無駄に複雑にしている気がするので上の問題をまずクリアしてみてください。


自分なら以下のようにします。解説が必要でしたらそのように言ってください。
https://codepen.io/og24715/pen/VBwdEx?editors=0010

js

1class Select extends React.Component { 2 state = { 3 items: [{ 4 id: 1, 5 name: 'React', 6 chosen: false, 7 }, { 8 id: 2, 9 name: 'Redux', 10 chosen: false, 11 }] 12 } 13 14 _handleClick = id => event => { 15 const items = [...this.state.items]; 16 const item = this.state.items.find(item => item.id === id); 17 item.chosen = !item.chosen; 18 19 this.setState({ items }); 20 }; 21 22 render() { 23 return ( 24 <ItemList 25 items={this.state.items} 26 handleClick={this._handleClick} 27 /> 28 ) 29 } 30} 31 32const ItemList = ({ items, handleClick }) => ( 33 items.map(item => ( 34 <Item 35 key={item.id} 36 item={item} 37 handleClick={handleClick} 38 /> 39 )) 40); 41 42const Item = ({ item, handleClick }) => ( 43 <button 44 onClick={handleClick(item.id)} 45 > 46 {item.chosen && '✔ '} 47 {item.name} 48 </button> 49);

投稿2018/07/10 16:21

編集2018/07/10 17:00
og24715

総合スコア832

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

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

k10a

2018/07/10 16:59

ご指摘の通りでございました。 冗長かつ複雑になっているが故に、示したいものが不明瞭となっていました。余分なものを削ると、クリアになりました。 有難うございます。
og24715

2018/07/10 17:07

解決した(?)ようで何よりです。 ミニマムなサンプルコードを追加しましたのでよければ参考にしてください。
k10a

2018/07/11 00:32

サンプルコードまでご享受頂きまして、誠にありがとうございます。シンプルにして、一旦正しい値は取得できているように見えましたが、og24715さまのサンプルコードも参考にさせて頂きます。 ご丁寧な対応、心から感謝致します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問