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

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

ただいまの
回答率

87.49%

React.js でラジオボタンもどきを実装する方法

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 3,729

score 114

 前提・実現したいこと

Reactでラジオボタンのようなものを作成したいと考えています。
理想とする挙動はボタンが複数あり、その中の一つをクリックするとボタンの色が変わり(色なりチェックマークなり)、次に違うボタンをクリックするとクリックしたボタンの色が変わり、先ほどクリックしたボタンはデフォルトの色に戻る、といった感じです。

クリックしたボタンの色が変わる適当なサンプルを作成したのですが、このサンプルだと、
クリックしたボタンの色は変わりますが、別のボタンをクリックしても前にクリックしたボタンの色は変化したままです。
理想とする挙動にするためにはクリックされるたびにボタン全部のstatefalseにして再レンダリングし、
クリックしたものだけをtrueにすればいいのだろうなと考えているのですがいまいち実装方法がわかりません...
サンプルからどのように修正すればラジオボタンのような挙動になるのでしょうか?
何か回答を頂けると非常に助かります<(_ _)>

 コード

 親コンポーネント

import React from 'react';
import SizeButton from './SizeButton';

const SizeContainer = (props) => {
  const { sizes } = props;
  return (
    <div>
      {sizes.map(size => (
        <SizeButton
          key={size.id}
          number={size.number}
        />
      ))}
    </div>
  );
};

export default SizeContainer;

 子コンポーネント

import React from 'react';

export default class SizeButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isClicked: false,
    };
  }

  handleClick() {
    this.setState({
      isClicked: true,
    });
  }

  render() {
    const button = this.state.isClicked
      ? <div style={{ backgroundColor: '#C8C8C8' }}>{this.props.number}</div>
      : <div style={{ backgroundColor: '#BA9D5F' }}>{this.props.number}</div>;

    return (
      <div onClick={() => this.handleClick()}>
        {button}
      </div>
    );
  }
}

 補足情報

<input type="radio">としていないのはボタンを色々とスタイリングしたいという理由もあります。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+3

イメージ説明

上位のコンポーネントにどのボタンが今、選択されているかのstateを持たせるのがポイントになってきます。

4,5パターンくらい実装方法がありそうですが、一番基礎的なやり方で、かつ、掲載されているコードを元にする方法だと、以下のような感じになると思います。

 Demo Code

https://codesandbox.io/s/k96yvnw77v

import React, { Component } from 'react';
import { render } from 'react-dom';

class App extends Component {

  render() {
    const sizes = [
      { id: 'aaa' },
      { id: 'bbb' },
      { id: 'ccc' }
    ]
    return <SizeContainer sizes={sizes} />
  }
}

class SizeContainer extends Component {

  constructor(props) {
    super(props);
    this.state = {
      selectedButtonId: null
    }
    this.handleButtonClick = this.handleButtonClick.bind(this);
  }

  handleButtonClick(event, buttonId) {
    this.setState({
      selectedButtonId: buttonId
    })
  }

  render() {
    const { sizes } = this.props;

    return (
      sizes.map((size) => {
          return (
            <SizeButton
              key={size.id}
              id={size.id}
              isSelected={this.state.selectedButtonId === size.id}
              onClick={this.handleButtonClick}
            />
          )
        })
    )
  }
}

const SizeButton = ({ id, isSelected, onClick }) => {
  return (
    <div
      onClick={(event) => onClick(event, id)}
      style={{ backgroundColor: isSelected ? 'red' : 'blue' }}
    >
      {id}
    </div>
  )
};



render(<App />, document.getElementById('root'));

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/03/16 13:04

    回答ありがとうございます<(_ _)>
    回答を参考に実装したところ、理想の挙動を実現できました。
    親のコンポーネントにクリックされたコンポーネントのIDをstateとして持たせることが重要だったのですね。
    ありがとうございました!

    キャンセル

  • 2018/03/16 18:17

    良かったです!

    キャンセル

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

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

関連した質問

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