🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Redux

Reduxは、JavaScriptアプリケーションの状態を管理するためのオープンソースライブラリです。ReactやAngularで一般的にユーザーインターフェイスの構築に利用されます。

JavaScript

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

React.js

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

Q&A

解決済

2回答

4231閲覧

Reactでクリックした要素にclassを付与して別の要素に付与してたclassを削除

moro123

総合スコア18

Redux

Reduxは、JavaScriptアプリケーションの状態を管理するためのオープンソースライブラリです。ReactやAngularで一般的にユーザーインターフェイスの構築に利用されます。

JavaScript

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

React.js

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

0グッド

0クリップ

投稿2019/10/22 01:30

Reactで2つの子コンポーネントを使用して、クリックした要素にclassをつけて、前についてた要素のclassを削除するというタブっぽい実装をやりたいのですが、なかなか上手くいかず、困ってます。
特にclassを外すときどうやって状態管理をして削除するようにすればいいかがわかりませんので、ご教授してもらえないでしょうか。

jsx

1 2class Parent extends React.Component { 3 constructor(props) { 4 super(props); 5 this.state = { 6 active: false 7 }; 8 } 9 onActive = active => { 10 this.setState({ 11 active 12 }); 13 } 14 render() { 15 const Child = ({active, onActive})=> { 16 const handleActive = event => { 17 onActive(!!event.target) 18 } 19 return( 20 <div onClick={handleActive} 21 className={`${active ? "current":""}`} →クリックされたらcurrentを付与、Child2にclassがついてたらclassを削除する 22 > 23 </div> 24 ) 25 } 26 const Child2 = ({active, onActive})=> { 27 const handleActive = event => { 28 onActive(!!event.target) 29 } 30 return( 31 <div onClick={handleActive} 32 className={`${active ? "current":""}`} 33 > 34 </div> 35 ) 36 } 37 return( 38 <div> 39 <Child active={active} onActive={onActive} /> 40 <Child2 active={active} onActive={onActive} /> 41 </div> 42 ) 43 } 44}

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

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

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

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

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

guest

回答2

0

こんにちは

ご質問のような、親コンポーネントの中に複数の子コンポーネントがあり、その中の1個がアクティブである(または選択されている)という場合、親の state にアクティブな子コンポーネントのインデクス(0始まり)を持たせるとうまくいきます。

この考え方で、以下、例となるコードを挙げていきます。

Parent#constructor

Parentthis.state.active は初期値を -1 とします。これは、どの子コンポーネントもアクティブではないことを表します。

javascript

1constructor(props) { 2 super(props); 3 this.state = { active: -1 }; 4}

なお、より意味がはっきりするプロパティ名をつけるとすれば、 単にactive ではなく、
activeChildIndex
だったり、あるいは、子がタブなのであれば
activeTabIndex
といったようにするところではありますが、以下では、activeのままで進めます。

Parent#onChangeActive

次に、this.state.active を変更するメソッドですが、 メソッド名はonActive ではなく、例えば
onChangeActive
あるいは、子がタブなのであれば、
onChangeTab
などとしたほうがよいでしょう。(他にもより良い名前があるかもしれません。) onActiveだと、Parentコンポーネント自体が active になったとき、という意味あいになってしまうからです。

以下、 onChangeActive というメソッド名にしました。

javascript

1onChangeActive = active => { 2 this.setState({ active }) 3}

上記のメソッドの引数 active には、 0 以上の整数が入ってくる想定です。たとえば 0 が入ってきたときは、 先頭の子コンポーネント、つまり見た目でいうと、通常、一番上だったり、一番左にある子をアクティブにすることを表します。

Parent のrender は後で挙げます。先にChildコンポーネントのコード例を挙げます。以下は、Child を、個別のファイル、Child.js に作成することを想定しています。

Child.js

jsx

1import React from 'react'; 2 3const Child = ({ text, onActive, active }) => ( 4 <div onClick={onActive} className={active ? 'current' : ''}> 5 {text} 6 </div> 7) 8 9export default Child; 10

Childはstateを持つ必要がなく、stateを持つ必要のないコンポーネントは、上記のように関数型コンポーネント(Functional Component)として書くとよいでしょう。

なお、上記の Childでは、 動作確認用の暫定で、text というpropsを追加して、これを <div> の内容として表示させるようにしました。

上記のようにChildを作っておき、Parent のほうで Child を import すると、Parent の render で、2つの子コンポーネントを配置するコードは以下のように書けます。

Parent#render

jsx

1render() { 2 return ( 3 <div> 4 <Child 5 text="Child#0" 6 onActive={() => this.onChangeActive(0)} 7 active={this.state.active === 0} 8 /> 9 <Child 10 text="Child#1" 11 onActive={() => this.onChangeActive(1)} 12 active={this.state.active === 1} 13 /> 14 </div> 15 ) 16 }

動作確認のため、以下のスタイルで、active になったChild では、文字を赤の太字にします。

css

1.current { color: red; font-weight: bold }

上記で、Parentをマウントしてrender させると、以下のように表示されます。

イメージ説明

「Child#0」をクリックすると、以下のように赤の太字になります。

イメージ説明

上記の状態から続けて、「Child#1」をクリックすると、以下のようになり、アクティブなChildが入れ替わったことが分かります。

イメージ説明

これでとりあえず意図通りに動くようになりますが、ちょっとリファクタします。
Parent の render で、Child を3個追加して、計5個にしたいとします。その場合、<Child /> を5個書けばよいわけですが、それだとコードが冗長になってしまいますので、子の数を表す

const CHILDREN_COUNT = 5;

という定数を用意しておいて、Parent の render を以下のようにします。

Parent#render

jsx

1 render() { 2 return ( 3 <div> 4 {[...Array(CHILDREN_COUNT)].map((_, childIndex) => 5 <Child 6 key={childIndex} 7 text={`Child#${childIndex}`} 8 onActive={() => this.onChangeActive(childIndex)} 9 active={this.state.active === childIndex} 10 /> 11 )} 12 </div> 13 ) 14 }

上記で、 以下のように5個の Child が表示されます。

イメージ説明

CHILDREN_COUNT を変更して、Child の個数を変えても、アクティブになる Childは(最大)1個です。

以上、参考になれば幸いです。

補足

React のバージョン 16.8 以降をお使いでしたら、Parentは、Hook を使って、以下のようにも書けます。

jsx

1const Parent = () => { 2 const [activeIndex, changeActive] = React.useState(-1); 3 4 return ( 5 <div> 6 {[...Array(CHILDREN_COUNT)].map((_, i) => 7 <Child 8 key={i} 9 text={`Child#${i}`} 10 onActive={() => changeActive(i)} 11 active={i === activeIndex} 12 /> 13 )} 14 </div> 15 ) 16}

投稿2019/10/22 04:48

編集2019/10/22 07:38
jun68ykt

総合スコア9058

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

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

moro123

2019/10/22 15:19

ご丁寧に説明とコードを提示していただき、ありがとうございました。 参考にさせていただき、解決できました!
jun68ykt

2019/10/22 15:22

どういたしまして。 > 解決できました! とのことでよかったです????
guest

0

ベストアンサー

stateが出力に対して十分な情報を持っていないというのは解消すべきと思います
現在の出力に依存して出力が変化するというのはよろしくなかろうかと思います

例えばstateに現在アクティブなタブのインデックスを入れるとかにすべきです

一応refを使えばどの要素が現在currentクラスを持っているかを調べることもできるでしょうが
このケースはその必要はないかと思います

投稿2019/10/22 03:57

KazuhiroHatano

総合スコア7819

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

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

moro123

2019/10/22 15:20

`例えばstateに現在アクティブなタブのインデックスを入れるとかにすべきです` 上記のアドバイスで解決できました。ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問