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

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

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

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

Q&A

0回答

931閲覧

Reactで親コンポーネントにあるuseStateのstateの値が変更されるにもかかわらず、子コンポーネントが再レンダーされない

Bonhomme

総合スコア2

React.js

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

0グッド

0クリップ

投稿2021/05/12 12:16

###わからないこと :
Reactで親コンポーネントにあるstateの値が更新されるにもかかわらず、子コンポーネントが再レンダーされないこと。こちらのサイトによれば、useStateを使用している場合、親コンポーネントから子コンポーネントに渡しているpropsの値が更新されれば、自動的に子コンポーネントも再レンダーされると考えたのですが、そのようになりません。もしこの 原因と解決方法が分かる方がいらっしゃいましたら教えていただけますと大変助かります。どうぞよろしくお願いします。

###実現したいこと :
以下のコードで「子コンポーネント1」で<Button id="ready-go-btn" onClick={()=>countdown()}>Ready Go !</Button>ボタンをクリックすることで親コンポーネントのcountdown関数を走らせ、変数numberの値を更新し、「子コンポーネント2」で表示しているnumberが1秒ごとに減っていくカウントダウンを実装したいです。

###問題となっているコード
以下のコードでは、「子コンポーネント1」の画面(localhost:3000/admin)では、<Button id="ready-go-btn" onClick={()=>countdown()}>Ready Go !</Button>ボタンをクリックすることでcountdown関数が実行され、numberの値が更新されるのですが(添付一枚目参照)、そのcountdown関数内で値が更新されるnumberをpropsとして渡して使用している「子コンポーネント2」の画面(localhost:3000)では再レンダーが起きません。(添付2枚目)。考えとして、再レンダーを起こして、添付2枚目の右上の10の数字を9,8,7...0のようにカウントダウンするようにしたいです。
イメージ説明
イメージ説明

react

1// 親コンポーネント // 2import React, { useState } from "react"; 3import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; 4import Monitor from "./Monitor"; 5import Admin from "./Admin"; 6import Client from "./Client"; 7import Error from "./Error"; 8 9function App() { 10 let [number, setNumber] = useState(10); 11 12 const countdown = () => { 13 console.log("clicked"); 14 console.log(number); 15 const count = 0; 16 const timerID = setInterval(function () { 17 if (number === count) { 18 clearInterval(timerID); 19 console.log("countdown finish") 20 } else { 21 setNumber(--number); 22 console.log(number); 23 } 24 }, 1000); 25 }; 26 27 return ( 28 <Router> 29 <Switch> 30 <Route exact path="/"> 31 <Monitor number={number} /> 32 </Route> 33 <Route exact path="/admin"> 34 <Admin countdown={countdown} /> 35 </Route> 36 <Route exact path="/client"> 37 <Client /> 38 </Route> 39 <Route path="*"> 40 <Error /> 41 </Route> 42 </Switch> 43 </Router> 44 ); 45} 46export default App;

react

1// 子コンポーネント1 2import React from "react"; 3import { Container, Row, Col, Button, Card, Table, Form } from "react-bootstrap"; 4import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 5import {faEnvelope} from "@fortawesome/free-solid-svg-icons"; 6 7const Admin = (props) => { 8 const {countdown} = props; 9 10 return ( 11 <Container className="container"> 12 <Row className="row"> 13 <Col xs={7}> 14 <Form> 15 <Form.Group controlId="monitorMessage"> 16 <Form.Label> 17 <FontAwesomeIcon icon={faEnvelope} /> 18 Monitor Message 19 </Form.Label> 20 <Form.Control 21 type="text" 22 placeholder="メッセージを入力してください" 23 /> 24 </Form.Group> 25 <Button variant="primary" type="submit"> 26 Submit 27 </Button> 28 <Button variant="warning" type="button"> 29 Clear 30 </Button> 31 </Form> 32 </Col> 33 <Col xs={5}> 34 <div className="sound-box "> 35 <h3 className="admin-index"> 36 <FontAwesomeIcon icon={faEnvelope} />Sounds 37 </h3> 38 <div className="sound-btns"> 39 <Button>Question</Button> 40 <Button id="ready-go-btn" onClick={()=>countdown()}>Ready Go !</Button> 41 <Button>Answer Check</Button> 42 </div> 43 </div> 44 </Col> 45 </Row> 46 <Row> 47 <Col xs={7}></Col> 48 <Col xs={5}></Col> 49 </Row> 50 </Container> 51 ); 52}; 53 54export default Admin; 55

react

1// 子コンポーネント2 2import React, { useState } from "react"; 3import data from "./data"; 4import { Container, Row, Col, Button } from "react-bootstrap"; 5 6const Monitor = (props) => { 7 const [questions, setQuestions] = useState(data); 8 const [questionNumber, setQuestionNumber] = useState(1); 9 const question = questions.find((question) => question.id === questionNumber); 10 const { number } = props; 11 12 return ( 13 <main> 14 <Container className="container"> 15 <div className="question-box"> 16 <p className="question-text">{question.question}</p> 17 <span id="count-down">{number}</span> 18 </div> 19 <Row className="row"> 20 <Col className="choice-box"> 21 <div className="cell"> 22 <div className="circle"> 23 <p className="alphabet red"> 24 <span className="character">A</span> 25 </p> 26 </div> 27 <p className="choice">{question.choices.A}</p> 28 </div> 29 </Col> 30 <Col xs={6} className="choice-box"> 31 <div className="cell"> 32 <div className="circle"> 33 <p className="alphabet blue"> 34 <span className="character">B</span> 35 </p> 36 </div> 37 <p className="choice">{question.choices.B}</p> 38 </div> 39 </Col> 40 <Col xs={6} className="choice-box"> 41 <div className="cell"> 42 <div className="circle"> 43 <p className="alphabet yellow"> 44 <span className="character">C</span> 45 </p> 46 </div> 47 <p className="choice">{question.choices.C}</p> 48 </div> 49 </Col> 50 <Col xs={6} className="choice-box"> 51 <div className="cell"> 52 <div className="circle"> 53 <p className="alphabet green"> 54 <span className="character">D</span> 55 </p> 56 </div> 57 <p className="choice">{question.choices.D}</p> 58 </div> 59 </Col> 60 </Row> 61 </Container> 62 </main> 63 ); 64}; 65 66export default Monitor; 67

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

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

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

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

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

hoshi-takanori

2021/05/12 13:42

Admin と Monitor の間はどうやって画面遷移してますか? もしかして別ウィンドウ (どころか別マシン) ですか?
Bonhomme

2021/05/12 22:04

ご質問ありがとうございます。 Adminは「localhost:3000/admin」、Monitorは「localhost:3000」で別ウインドウとなります。イメージとしては、Adminの画面でボタンを押下することで、Monitor画面のカウントダウンをスタートさせることを目的としています。ですので、Admin画面とMonitor画面の間で画面の行き来はありません。 別ウインドウではstateの更新による再レンダーは発生できないでしょうか?
hoshi-takanori

2021/05/12 22:22

React の state (に限らず、JS の処理系) は基本的にウィンドウやタブごとに独立してますので、再レンダーは発生しません。いくつか方法はあるようですが…。 https://javascript.plainenglish.io/a-react-hook-to-share-state-between-browser-windows-a672470f66ff ただ、これって Kahoot 的なものですよね。ってことは出題者と回答者たちがそれぞれ別のマシンからアクセスすることになると思いますが、その場合は何らかのサーバーが必要でしょうね。
Bonhomme

2021/05/12 23:48

ご回答ありがとうございます。 >React の state (に限らず、JS の処理系) は基本的にウィンドウやタブごとに独立してますので、再レンダーは発生しません。いくつか方法はあるようですが… >その場合は何らかのサーバーが必要でしょうね。 → そうなんですね、 添付いただいたURLやwebsocketを使用することで何とか実現したいことを実装してみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

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

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

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問