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

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

ただいまの
回答率

90.51%

  • React.js

    834questions

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

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

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 127

k10a

score 10

 前提・実現したいこと

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
中間コンポーネント

import React, { Component } from 'react';
import Item from './Item';

class ItemList extends Component {

  render() {
    const items = this.props.items.map( item =>
      <Item
        key={item.id}
        {...item}
        setItemStatus={this.props.setItemStatus}
      />
    )

    return(
      <ul>
        {items}
      </ul>
    );
  }
}

export default ItemList

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

import React, { Component } from 'react';

class Item extends Component {
  render() {

    const link = this.props.chosen ? 'unselected' : 'selected'
    return (
      <button onClick={this.props.parentMethod}>
        <span>{this.props.id}</span>
        <span>{this.props.name}</span>
        <a href="" onClick={(e) => {
          e.preventDefault();
          this.props.setItemStatus(this.props)
        }}>{link}</a>
      </button>
    );
  }
}

export default Item
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

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

// select class
setItemStatus(clickItem) {
  ...
  if( selectedItems.indexOf(clickItem) >= 0) {
    selectedItems.remove(clickItem) // <- これ
  } else {
    selectedItems.push(clickItem)
  }
  ...
}

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

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

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

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


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

class Select extends React.Component {
  state = {
    items: [{
      id: 1,
      name: 'React',
      chosen: false,
    }, {
      id: 2,
      name: 'Redux',
      chosen: false,
    }]
  }

  _handleClick = id => event => {
    const items = [...this.state.items];
    const item = this.state.items.find(item => item.id === id);
    item.chosen = !item.chosen;

    this.setState({ items });
  };

  render() {
    return (
      <ItemList
        items={this.state.items}
        handleClick={this._handleClick}
      />
    )
  }
}

const ItemList = ({ items, handleClick }) => (
  items.map(item => (
    <Item
      key={item.id}
      item={item}
      handleClick={handleClick}
    />
  ))
);

const Item = ({ item, handleClick }) => (
  <button
    onClick={handleClick(item.id)}
  >
    {item.chosen && '✔ '}
    {item.name}
  </button>
);

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/11 01:59

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

    キャンセル

  • 2018/07/11 02:07

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

    キャンセル

  • 2018/07/11 09:32

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

    キャンセル

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

  • ただいまの回答率 90.51%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • React.js

    834questions

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