###わからないこと :
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
あなたの回答
tips
プレビュー