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

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

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

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

React.js

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

Q&A

1回答

1468閲覧

一方の子コンポーネントのイベントで他方の子コンポーネントの関数を実行したい

chamiotuchinoko

総合スコア0

JavaScript

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

React.js

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

1グッド

0クリップ

投稿2021/08/01 10:21

概要

子コンポーネントをクリックした際に他方のコンポーネント(兄弟関係)の状態を変更するような実装を行いたいと考えています。

前提

React初学レベルです。
Hooksを用いてSPAを実装しようと勉強中の段階です。

行いたいこと

複数の兄弟関係の子コンポーネントがありそれらのいずれかのコンポーネントをクリックした際に、すべての兄弟関係のコンポーネントにクラスを付与したい。
その際、子コンポーネントに渡されたpropsの値に応じて付与するクラスを変更したい。

実装内容

true, falseをランダムにpropsで渡し(以下例では便宜上ランダムには渡していません)、子コンポーネントのいずれかをクリックした際に、propsに応じて全ての子コンポーネントに処理を行うような実装です。
具体的にはクリックすると全ての子コンポーネントにpropstrue/falseに応じたクラスを付与するというものです。

javascript

1// Parent.jsx 2 3const Parent = () => { 4 const arrayBool = [true, false, false] 5 6 return ( 7 <ul> 8 {arrayBool.map((bool, i) => { 9 return <Child key={i.toString()} bool={bool}/> 10 })} 11 </ul> 12 ) 13 14} 15 16export default Parent

javascript

1// Child.jsx 2 3const Child = (props) =>{ 4 const hoge = () => { 5 if(props.bool) { 6 // trueの処理 7 } else { 8 // falseの処理 9 } 10 } 11 12 return ( 13 <li> 14 <button onClick={() => hoge()}> 15 <span>Click!</span> 16 </button> 17 </li> 18 ) 19} 20 21export default Child

行ったこと

  • 上記例では当然一つの子コンポーネントをクリックしても当該コンポーネントのクリックイベントしか実行されません。
  • また子コンポーネントのイベントで他の子コンポーネントのイベントハンドラを実行することができませんでした(そういった実装自体がReactの設計に反しているとも思います)ので、以下のように実装しようと試みました。
  1. 子コンポーネントがクリックされたことを親に伝える(子のクリックイベントで親のstateを変更する など)
  2. useRefを用いて親から全ての子コンポーネントの関数を実行する
  3. 子コンポーネントに渡っているpropsに応じたクラスを付与する

javascript

1// Parent.jsx 2 3const Parent = () => { 4 const [value, setValue] = useState('') 5 6 const childRef01 = useRef(); 7 const childRef02 = useRef(); 8 const childRef03 = useRef(); 9 10 // valueが変更されたら子コンポーネントの関数を実行する 11 useEffect(() => { 12 childRef01.current.childFunc(); 13 childRef02.current.childFunc(); 14 childRef03.current.childFunc(); 15 }, [value]); 16 17 const changeValue = (text) => { 18 setValue(text) 19 } 20 21 return ( 22 <> 23 <Child id={true} ref={childRef01} text={'HOGE'} event={changeValue} bool={true} /> 24 <Child id={false} ref={childRef02} text={'FUGA'} event={changeValue} bool={false} /> 25 <Child id={true} ref={childRef03} text={'PIYO'} event={changeValue} bool={false} /> 26 </> 27 ); 28}; 29 30export default Parent

javascript

1// Child.jsx 2 3import React, { forwardRef, useImperativeHandle, useState } from 'react'; 4 5const ChildrenBase = (props, ref) => { 6 const [bool, setBool] = useState(''); 7 const [className, setClassName] = useState('') 8 9 // 親から呼ばれる関数を定義 10 useImperativeHandle(ref, () => ({ 11 childFunc() { 12 if(props.bool) { 13 // trueの処理 14 } else { 15 // falseの処理 16 } 17 }, 18 })); 19 20 return ( 21 <p className={className} onClick={() => props.event('props.text')}>{props.text}</p> 22 ); 23}; 24const Child = forwardRef(ChildrenBase); 25 26export default Child

上記手順で一つの子コンポーネントをクリックした際に全ての子コンポーネントに定義されている関数を実行することはできたのですが、childFunc()内で子コンポーネントにクラスをaddする処理が記述できずに断念しました。
(そもそも「子コンポーネントが親コンポーネントの関数を実行する」という実装自体に疑問があるため、無理矢理な実装であることは理解しています。)

そのほかにもこちらの記事を参考に兄弟間でイベントを実行し合うような実装も試みましたが、望んだ実装はできませんでした。

既述した「行いたいこと」のような挙動を実装するにはどのようにしたらよいでしょうか。
よろしくお願いいたします。

###マシン環境
MacBook Air (M1, 2020) Big Sur v11.3.1
node: v16.2.0
npm: v7.13.0
yarn: v1.22.10

Waki285👍を押しています

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

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

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

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

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

hoshi-takanori

2021/08/01 10:42 編集

基本的には Child がクリックされた時の処理を Parent から渡す形になると思いますが、具体的にやりたいことがいまいち見えないというか、ある Child の処理は他の Child の状態によっても変わるのでしょうか?
chamiotuchinoko

2021/08/01 12:09

より具体的にやりたいことを明記しますと、クイズアプリを作ろうとしておりまして、Childが回答の選択肢それぞれとなります。Childには親から回答内容のテキストと正答・誤答を判定するための`true/false`が渡されます。いずれかの回答をクリックした際に正答であるコンポーネントに正解を表すクラスを、誤答であるコンポーネントに誤答を表すクラスを付与したいと考えています。ですので、「ある Child の処理は他の Child の状態によっても変わるのでしょうか?」というご質問への回答はYesです!
hoshi-takanori

2021/08/01 19:03

複数の選択肢のうち正答が一つだけなら、管理すべき状態はどれが選ばれたか (またはどれも選ばれてないか) だけですね。Child の表示方法はそこから派生する状態に過ぎないので、Parent 側でどれが選ばれたかを管理 (useState) し、Child 側にそれを変更する関数 (setValue) と表示状態 (value から派生する値、または value と正答を渡して Child 側で計算しても良い) を渡してやれば良いでしょう。 また、「子コンポーネントにクラスをaddする処理が記述できず」とお書きになってますが、React では自分でクラスを add/remove する必要はなく、各要素のクラスがどうなって欲しいかだけ書けば、add/remove は React が処理してくれます。
guest

回答1

0

そもそも「子コンポーネントが親コンポーネントの関数を実行する」という実装自体に疑問があるため

いえ、これが基本のやり方です。

子コンポーネントで発生したイベントでコンポーネント自身の外部を変更したい場合、propあるいはContextから供給された、親コンポーネント(あるいはそれより上)で定義された変更関数を呼び出す、という形を取ります。

投稿2021/08/01 11:13

maisumakun

総合スコア146018

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問