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

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

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

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

Q&A

解決済

1回答

798閲覧

useStateの値が更新されない

Kino104

総合スコア10

React.js

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

0グッド

0クリップ

投稿2021/08/18 14:31

ソースコード

react

1// App.js 2 3 4import './App.css'; 5import DateBox from './components/DateBox'; 6import Nav from "./components/Nav"; 7import AddSchedule from './components/AddSchedule'; 8import styled from 'styled-components'; 9import { useState } from 'react'; 10 11// styled-components → 12const Container = styled.div` 13 margin: 10px; 14`; 15 16const DatesUl = styled.ul` 17 display: grid; 18 grid-template-columns: repeat(7, 1fr); 19 border: 1px solid rgba(0, 0, 0, 0.54); 20 border-bottom: none; 21 border-right: none; 22 padding: 0; 23`; 24// ← styled-components 25 26function App() { 27 28 const [dates, setDates] = useState(new Date()); 29 const days = []; 30 const weeks = ["日", "月", "火", "水", "木", "金", "土"]; 31 let nowYear = dates.getFullYear(); 32 let nowMonth = dates.getMonth() + 1; 33 let firstDate = new Date(nowYear, (nowMonth-1), 1); 34 let firstDay = firstDate.getDay(); 35 let startDate = new Date(firstDate); 36 startDate.setDate(firstDate.getDate() - firstDay); 37 const thisMonth = (month) => { 38 if (month === dates.getMonth()+1) return true; 39 return false; 40 } 41 const askToday = (year, month, date) => { 42 let today = new Date(); 43 if (year === today.getFullYear() && month === today.getMonth()+1 && date === today.getDate()) {return true;} 44 return false; 45 } 46 47 // new → 48 const [addShow, setAddShow] = useState(false); 49 const [addYear, setAddYear] = useState(null); 50 const [addMonth, setAddMonth] = useState(null); 51 const [addDate, setAddDate] = useState(null); 52 const changeAddShow = (year, month, date) => { // ② 53 setAddYear(year); 54 setAddMonth(month); 55 setAddDate(date); 56 setAddShow(!addShow); 57 } 58 // ← new 59 60 for(let i = 0; i < 35; i++) { 61 let year = startDate.getFullYear(); 62 let month = startDate.getMonth() + 1; 63 let date = startDate.getDate(); 64 let isThisMonth = thisMonth(month); 65 let isToday = askToday(year, month, date); 66 if (i < 7) { 67 days.push({ 68 topDays: true, 69 week: weeks[i], 70 year: year, 71 month: month, 72 date: date, 73 isThisMonth: isThisMonth, 74 isToday: isToday 75 }); 76 } else { 77 days.push({ 78 topDays: false, 79 year: year, 80 month: month, 81 date: date, 82 isThisMonth: isThisMonth, 83 isToday: isToday 84 }); 85 } 86 startDate.setDate(startDate.getDate() + 1); 87 } 88 const dateComponents = days.map((day, index) => { 89 return ( 90 <DateBox 91 key={index} 92 topDays={day.topDays} 93 week={day.week} 94 year={day.year} 95 month={day.month} 96 date={day.date} 97 isThisMonth={day.isThisMonth} 98 isToday={day.isToday} 99 changeAddShow={changeAddShow} 100 /> 101 ); 102 }); 103 104 const changeMonth = (key) => { // 月移動関数 105 if (key === "prev") { 106 let newDates = new Date(dates.setMonth(dates.getMonth() - 1)); 107 setDates(newDates); 108 } else if (key === "next") { 109 let newDates = new Date(dates.setMonth(dates.getMonth() + 1)); 110 setDates(newDates); 111 } 112 } 113 114 return ( 115 <Container> 116 <Nav dates={dates} changeMonth={changeMonth} /> 117 <DatesUl> 118 {dateComponents} 119 </DatesUl> 120 <AddSchedule show={addShow} year={addYear} month={addMonth} date={addDate} /> // ③ 121 </Container> 122 ); 123} 124 125export default App;

react

1//DateBox.js 2 3 4import styled from 'styled-components'; 5 6// styled-components → 7const DateLi = styled.li` 8 list-style: none; 9 height: 120px; 10 border-bottom: 1px solid rgba(0, 0, 0, 0.54); 11 border-right: 1px solid rgba(0, 0, 0, 0.54); 12 @media(min-width: 600px) { 13 height: 155px; 14 } 15`; 16 17const Date = styled.div` 18 text-align: center; 19 margin-top: 5px; 20 font-size: ${(props) => props.isToday ? '17px' : '12px'}; 21 font-weight: 500; 22 color: ${(props) => props.isToday ? 'red' : '#000'}; 23 opacity: ${(props) => props.isThisMonth ? '1': '0.5' }; 24 `; 25 26const Day = styled.div` 27 text-align: center; 28 color: rgba(0, 0, 0, 0.54); 29 margin-top: 5px; 30 font-size: 12px; 31`; 32// ← styled-components 33 34const DateBox = (props) => { 35 36 return( 37 <> 38 <DateLi onClick={() => props.changeAddShow(props.year, props.month, props.date)}> // ① 39 { 40 props.topDays ? 41 <> 42 <Day>{props.week}</Day> 43 <Date 44 isToday={props.isToday} 45 isThisMonth={props.isThisMonth} 46 > 47 {props.date} 48 </Date> 49 </> 50 : 51 <Date 52 isToday={props.isToday} 53 isThisMonth={props.isThisMonth} 54 > 55 {props.date} 56 </Date> 57 } 58 </DateLi> 59 </> 60 ); 61} 62 63export default DateBox;

react

1// AddSchedule.js 2 3 4import AddSubSchedule from '../AddSubSchedule'; 5import styled from 'styled-components'; 6import { useState } from 'react'; 7 8// styled-components → 9const Overlay = styled.div` 10 position:fixed; 11 top:0; 12 left:0; 13 width: 100%; 14 height: 100%; 15 background-color: rgba(0,0,0,0.5); 16 display: flex; 17 align-items: center; 18 justify-content: center; 19 animation: fadein-anim 0.1s linear forwards; 20 opacity: 0; 21 @keyframes fadein-anim { 22 100% { 23 opacity: 1; 24 } 25 } 26`; 27 28const Content = styled.form` 29 z-index:2; 30 width:50%; 31 max-width: 370px; 32 background:#fff; 33 padding: 10px 20px; 34 border-radius: 5px; 35`; 36 37const Close = styled.div` 38 height: 40px; 39 display: flex; 40 align-items: top; 41 justify-content: flex-end; 42 43`; 44 45const CloseContent = styled.div` 46 width: 30px; 47 height: 30px; 48 display: flex; 49 justify-content: center; 50 align-items: center; 51 color: rgba(0, 0, 0, 0.5); 52 border-radius: 50%; 53 font-size: 27px; 54 transition: all 0.2s; 55 &:hover { 56 background-color: rgba(0,0,0,0.1); 57 cursor: pointer; 58 } 59`; 60 61const Title = styled.input` 62 box-sizing: content-box; 63 border: none; 64 width: 100%; 65 font-size: 20px; 66 padding: 0 0 5px 0; 67 outline: none; 68`; 69 70const Line = styled.div` 71 position: relative; /*.text_underline::beforeの親要素*/ 72 border-top: 1px solid #c2c2c2; /*text3の下線*/ 73 margin-bottom: 30px; 74 &::before, 75 &::after { 76 position: absolute; 77 bottom: 0px; /*中央配置*/ 78 width: 0px; /*アニメーションで0pxから50%に*/ 79 height: 2px; /*高さ*/ 80 content: ''; 81 background-color: #005FFF; /*アニメーションの色*/ 82 transition: all 0.5s; 83 } 84 &::before { 85 left: 50%; 86 } 87 &::after { 88 right: 50%; 89 } 90 ${Title}:focus + &::before, 91 ${Title}:focus + &::after { 92 width: 50%; 93 } 94`; 95// ← styled-components 96 97 98const AddSchedule = (props) => { 99 100 let year = props.year; 101 let month = props.month < 10 ? "0" + props.month : props.month; 102 let date = props.date < 10 ? "0" + props.date : props.date; 103 104 const [titleItem, setTitleItem] = useState(""); 105 const handleChangeTitle = (e) => { 106 setTitleItem(e.target.value); 107 } 108 109 const handleSubmit = (e) => { 110 e.preventDefault(); 111 const newItem = { 112 title: titleItem, 113 date: dateItem, 114 place: placeItem, 115 explain: explainItem 116 } 117 props.addItems(newItem); 118 setTitleItem(""); 119 setPlaceItem(""); 120 setExplainItem(""); 121 props.changeAddShow(); 122 } 123 124 const [dateItem, setDateItem] = useState(`${year}-${month}-${date}`); // ④ 125 const handleChangeDate = (value) => { 126 setDateItem(value); 127 } 128 const [placeItem, setPlaceItem] = useState(""); 129 const handleChangePlace = (value) => { 130 setPlaceItem(value); 131 } 132 const [explainItem, setExplainItem] = useState(""); 133 const handleChangeExplain = (value) => { 134 setExplainItem(value); 135 } 136 137 if (props.show) { 138 return ( 139 <Overlay> 140 <Content> 141 <Close> 142 <CloseContent>×</CloseContent> 143 </Close> 144 <Title 145 type="text" 146 value={titleItem} 147 placeholder="タイトルと日時を追加" 148 name="title" 149 onChange={handleChangeTitle} 150 /> 151 <Line></Line> 152 <AddSubSchedule 153 type="date" 154 value={dateItem} 155 img={`${process.env.PUBLIC_URL}/watch.svg`} 156 handleChange={handleChangeDate} 157 /> 158 <AddSubSchedule 159 type="text" 160 value={placeItem} 161 placeholder="場所を追加" 162 img={`${process.env.PUBLIC_URL}/map.svg`} 163 name="place" 164 handleChange={handleChangePlace} 165 /> 166 <AddSubSchedule 167 type="text" 168 value={explainItem} 169 placeholder="説明を追加" 170 img={`${process.env.PUBLIC_URL}/pen.svg`} 171 name="explanation" 172 handleChange={handleChangeExplain} 173 /> 174 <button type="button" onClick={handleSubmit}>保存</button> 175 </Content> 176 </Overlay> 177 ); 178 } else { 179 return null; 180 } 181 182 183} 184 185export default AddSchedule;

解決したいこと

DateBoxコンポーネント①部分の要素でクリックイベントが起きた時、
Appコンポーネント②部分のchangeAddShow()関数が実行され、それぞれのstateが変更し、
その値をAppコンポーネント③部分でAddScheduleコンポーネントのpropsとして渡し、
そのデータがAddScheduleコンポーネント④部分のusestateの初期値になるようにプログラムを書きたいのですが、
①のクリックイベント後の④のdateItemの値が「null-0null-0null」と意図しない出力結果になってしまいます。
Appコンポーネントから受け取った props.year, props.month, props.date の値は出力できているので、④部分が適当ではないと思うのですが、なぜこのコードでは上手く出力されないのでしょうか?また、解決策を教えていただきたいです。

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

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

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

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

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

guest

回答1

0

ベストアンサー

④の初期値はあくまでも初期値であり、かつ AddSchedule は常に存在するので、最初の year, month, date の値 (つまり、すべて null) しか使われず、その後 props が変化しても、dateItem の値は変化しません。

AddSchedule の中で props.show の値によって表示を制御する代わりに、App の中で addShow の値によって AddSchedule を表示するかどうかを制御すれば、addShow が true になるたびに新しい AddSchedule が作られて、その時点の year, month, date の値が dateItem の初期値になります。

diff

1 function App() { 2 // 略 3- <AddSchedule show={addShow} year={addYear} month={addMonth} date={addDate} /> // ③ 4+ {addShow && <AddSchedule year={addYear} month={addMonth} date={addDate} />}

diff

1 const AddSchedule = (props) => { 2 // 略 3- if (props.show) { 4 return ... // 常に表示内容を返す 5- } else { 6- return null; 7- }

投稿2021/08/18 22:34

hoshi-takanori

総合スコア7895

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問