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

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

詳細はこちら
JavaScript

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

React.js

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

Q&A

1回答

721閲覧

配列型のstateを保存できない

suto_michimasa

総合スコア5

JavaScript

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

React.js

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

0グッド

0クリップ

投稿2021/03/09 06:16

編集2021/03/10 06:22

stateの中のbmiに計算した数値を代入して保存したい

ユーザーが身長、体重を入れると、コードで計算をしてオブジェクトで定義したstateの中のbmiに保存できるようにしたい。

発生している問題・エラーメッセージ

setStateでbmiが保存されていない。ログを出してみるときちんとBMIは計算できていて、値が表示されていたので、以下の即時関数に問題がある可能性がある気がするが、原因がわからなかった。

react

1(function () { 2 const height_m = state.height / 100; 3 const total = parseFloat(state.weight / (height_m * height_m)); 4 const BMI = Math.round(total) 5 setState({ ...state, bmi: BMI }); 6 console.log(state) 7 }())

該当のソースコード(変更前)

react

1function Setting() { 2 const [state, setState] = useState({ 3 name: "", 4 old: "", 5 weight: "", 6 height: "", 7 introduction: "", 8 fat_percentage: "", 9 bmi: "", 10 }); 11 const handleChange = event => { 12 console.log(event.target.name) 13 setState({ ...state, [event.target.name]: event.target.value }); 14 }; 15 const handleSubmit = () => { 16 const currentUser = firebase.auth().currentUser; 17 (function () { 18 const height_m = state.height / 100; 19 const total = parseFloat(state.weight / (height_m * height_m)); 20 const BMI = Math.round(total) 21 setState({ ...state, bmi: BMI }); 22 console.log(state) 23 }()) 24 } 25 return ( 26 <React.Fragment> 27 <SchemerAppBar title="Setting" /> 28 <Container> 29 <form onSubmit={handleSubmit}> 30 <Grid> 31 <TextField name="name" width="180" label="名前" value={state.name} onChange={handleChange} style={{ marginRight: 20 }}></TextField> 32 <TextField 33 width="150" 34 label="年齢" 35 name="old" 36 defaultValue={state.old} 37 value={state.old} 38 onChange={handleChange} 39 InputProps={{ 40 endAdornment: <InputAdornment position="end">歳</InputAdornment>, 41 }}></TextField> 42 </Grid> 43 <Grid> 44 <TextField 45 name="height" 46 width="100" 47 label="身長" 48 value={state.height} 49 style={{ marginRight: 20 }} 50 onChange={handleChange} 51 InputProps={{ 52 endAdornment: <InputAdornment>cm</InputAdornment>, 53 }}></TextField> 54 <TextField 55 width="100" 56 label="体重" 57 name="weight" 58 value={state.weight} 59 onChange={handleChange} 60 InputProps={{ 61 endAdornment: <InputAdornment>Kg</InputAdornment>, 62 }} 63 ></TextField> 64 <TextField 65 width="100" 66 label="体脂肪率" 67 name="fat_percentage" 68 value={state.fat_percentage} 69 onChange={handleChange} 70 style={{ marginLeft: 20 }} 71 InputProps={{ 72 endAdornment: <InputAdornment>%</InputAdornment>, 73 }} 74 ></TextField> 75 </Grid> 76 <Grid> 77 <InputLabel style={{ marginTop: 20 }}>詳細</InputLabel> 78 <TextField 79 name="introduction" 80 width="400" 81 multiline rows={4} 82 variant="outlined" 83 value={state.introduction} 84 fullWidth 85 onChange={handleChange} 86 variant="outlined" 87 > 88 </TextField> 89 </Grid> 90 <Grid container justify="space-between"> 91 <Grid item> 92 </Grid> 93 <Grid item> 94 <Button 95 color="primary" 96 variant="contained" 97 style={{ marginTop: 20 }} 98 value="Submit" 99 type="submit" 100 > 101 登録する</Button> 102 </Grid> 103 </Grid> 104 </form> 105 </Container> 106 </React.Fragment> 107}

#変更後(formではなく、変更ボタンクリック次に呼び出すようにした)

react

1function Setting() { 2 const [state, setState] = useState({ 3 name: "", 4 old: "", 5 weight: "", 6 height: "", 7 introduction: "", 8 fat_percentage: "", 9 bmi: "", 10 }); 11const handleChange = event => { 12 console.log(event.target.name) 13 setState({ ...state, [event.target.name]: event.target.value }); 14 } 15 function calcBMI() { 16 const height_m = state.height / 100; 17 var total = parseFloat(state.weight / (height_m * height_m)); 18 const BMI = Math.round(total); 19 const newState = { ...state, bmi: BMI }; 20 setState(newState); 21 console.log(state); 22 } 23 function handleSubmit() { 24 const currentUser = firebase.auth().currentUser; 25 calcBMI(); 26 } 27 return ( 28 <React.Fragment> 29 <SchemerAppBar title="Setting" /> 30 <Container> 31 <Button 32 color="default" 33 variant="contained" 34 onClick={() => history.goBack()} 35 style={{ marginTop: 20 }} 36 >戻る 37 </Button> 38 <Grid> 39 <TextField name="name" width="180" label="名前" value={state.name} onChange={handleChange} style={{ marginRight: 20 }}></TextField> 40 <TextField 41 width="150" 42 label="年齢" 43 name="old" 44 value={state.old} 45 onChange={handleChange} 46 InputProps={{ 47 endAdornment: <InputAdornment position="end">歳</InputAdornment>, 48 }}></TextField> 49 </Grid> 50 <Grid> 51 <TextField 52 name="height" 53 width="100" 54 label="身長" 55 value={state.height} 56 style={{ marginRight: 20 }} 57 onChange={handleChange} 58 InputProps={{ 59 endAdornment: <InputAdornment>cm</InputAdornment>, 60 }}></TextField> 61 <TextField 62 width="100" 63 label="体重" 64 name="weight" 65 value={state.weight} 66 onChange={handleChange} 67 InputProps={{ 68 endAdornment: <InputAdornment>Kg</InputAdornment>, 69 }} 70 ></TextField> 71 <TextField 72 width="100" 73 label="体脂肪率" 74 name="fat_percentage" 75 value={state.fat_percentage} 76 onChange={handleChange} 77 style={{ marginRight: 20, marginLeft: 20 }} 78 InputProps={{ 79 endAdornment: <InputAdornment>%</InputAdornment>, 80 }} 81 ></TextField> 82 </Grid> 83 <Grid> 84 <InputLabel style={{ marginTop: 20 }}>詳細</InputLabel> 85 <TextField 86 name="introduction" 87 width="400" 88 multiline rows={4} 89 variant="outlined" 90 value={state.introduction} 91 fullWidth 92 onChange={handleChange} 93 variant="outlined" 94 > 95 </TextField> 96 </Grid> 97 <Grid container justify="space-between"> 98 <Grid item> 99 </Grid> 100 <Grid item> 101 <Button 102 color="primary" 103 variant="contained" 104 style={{ marginTop: 20 }} 105 value="Submit" 106 type="submit" 107 onClick={handleSubmit} 108 > 109 登録する</Button> 110 </Grid> 111 </Grid> 112 <LabelBottomNavigation /> 113 </Container> 114 </React.Fragment> 115 ); 116}

試したこと

handleSubmit関数の中でstateのログを出してみたところ、bmi以外はhandleSubmit内でstateが置き換えられていることがわかった。
即時関数内で、console.log(BMI)をすると、計算された値が表示された。

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

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

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

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

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

guest

回答1

0

handleSubmit関数の中でstateのログを出してみたところ、bmi以外はhandleSubmit内でstateが置き換えられていることがわかった。

setState非同期に実行されます。直後の行でstateを見ても、変化はしません。

投稿2021/03/09 06:25

maisumakun

総合スコア145973

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

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

suto_michimasa

2021/03/09 06:51

回答ありがとうございます。 たしかにそうですね。 この場合、どうすればsetStateの処理後のログを確認できるのでしょうか?
maisumakun

2021/03/09 06:55

一例としては、コンポーネント直下にconsole.logを置いておけば、コンポーネント描画のたびに出力されます。
suto_michimasa

2021/03/09 13:15

やってみたんですけど、stateの中のbmiは空の状態でした。。
maisumakun

2021/03/09 13:22

onSubmitでのセットである以上、それが実行された後にはHTMLレベルの動作としてページ遷移してしまうので、JavaScript的に値が変化するのはチェックできないかもしれません。
suto_michimasa

2021/03/10 06:25

formのonSubmitではなく、javascriptのonClickに変えてみましたが、相変わらずうまく保存ができませんでした。変更後のコードも載せてみたので、どこかおかしいところがあったら教えてください。 よろしくお願いします!
maisumakun

2021/03/10 06:33

最初の回答に戻るような気がします。 setState(newState);の次の行では、console.log(state);としても前の値のままです。
suto_michimasa

2021/03/11 05:27

すみません、忘れていました。 ただ、試しにhandleSubmitの中や関数の外の位置でstateを表示したところ、同じようにbmiだけが空の状態で返ってきます。。
maisumakun

2021/03/11 05:31

> handleSubmitの中や関数の外の位置でstateを表示したところ、同じようにbmiだけが空の状態で返ってきます。。 「handleSubmitの中」ではcalcBMIと同期的なので、setStateの処理より前になります。
suto_michimasa

2021/03/11 09:38 編集

どこでログを出しても、stateの中のbmiだけが空の状態で返ってきます。 したがって、保存がうまくできていないことが原因のように思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問