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

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

詳細はこちら
React.js

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

Q&A

解決済

1回答

2560閲覧

React.jsでTrue・falseの更新が上手くいかない

kata.

総合スコア6

React.js

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

0グッド

0クリップ

投稿2019/11/11 12:17

編集2019/11/11 22:19

前提・実現したいこと

React.jsでアプリを作成しています。

クリックした場所に図形を描画する機能を実装しています。
用意したボタンを押した時に別の図形を描画させたいです。

具体的に言うと、setStateを使ってTrue・falseの更新を行いたいのですが、上手く更新ができません。

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

最初のデフォルトで設定している図形は意図した通りに描画されますが、
画面表示された時点の下記の警告メッセージが出ています。

Warning: Can't call setState on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the App component. console.<computed>

警告の内容では、マウントされていないコンポーネントでsetStateを行うがいけないと書いてあるように思うのですが、対処法が分からない状態です。

調べて試した範囲では、thisのバインドやアロー関数を使ってみましたが上手く更新されません。

該当のソースコード

React.js

1import React, { Component } from 'react'; 2import Rect from './Rect'; 3import './App.css'; 4 5class App extends Component{ 6 7 data = []; 8 9 msgStyle = { 10 fontSize: "24px", 11 color: "#900", 12 margin:"20px 0px", 13 padding: "5px", 14 } 15 btnStyle = { 16 fontsize: "20px", 17 padding: "10px 30px", 18 border: "border 1px solid", 19 margin:"0 20px 20px 0", 20 } 21 area = { 22 width:"500px", 23 height:"500px", 24 border:"1px solid blue" 25 } 26 constructor(props){ 27 super(props); 28 this.state = { 29 list: this.data, 30 flgA: true, 31 flgB: false, 32 }; 33 this.doAction = this.doAction.bind(this); 34 this.doshapeA = this.doshapeA.bind(this); 35 this.doshapeB = this.doshapeB.bind(this); 36 } 37 38doAction(e){ 39 let x = e.pageX; 40 let y = e.pageY; 41 this.data.push({x:x, y:y}); 42 this.setState({ 43 list:this.data 44 }); 45} 46 47doshapeA(){ 48 this.setState({ 49 flgA: true, 50 flgB: false 51 }); 52} 53 54doshapeB(){ 55 this.setState({ 56 flgA: false, 57 flgB: true 58 }); 59} 60 61draw(d){ 62 let s = { 63 position:"absolute", 64 left:(d.x - 10) + "px", 65 top:(d.y - 10) + "px", 66 }; 67 //ここでtrue falseを判定 68 const input = (this.state.flgA) ? <div style={s}><i class="fa fa-heart">A</i></div> : <div style={s}>図形B<i class="fa fa-star">い</i></div>; 69 return <div>{input}</div>; 70} 71 72render(){ 73 return ( 74 <div> 75 <button style={this.btnStyle} onClick={this.doshapeA}>図形A</button> 76 <button style={this.btnStyle} onClick={this.doshapeB}>図形B</button> 77 <div style={this.area} onClick={this.doAction}> 78 {this.data.map((value)=>this.draw(value))} 79 </div> 80 </div> 81 ); 82 } 83} 84 85export default App;

試したこと

・更新を行うステートではアロー関数を使って実行させてみたが、変わらない。

・更新を行うステートの中にconsole.logを記述した所、最初に表示された時点でflgA,flabBの両方のログが表示されたが、それ以降はボタンを押しても何も表示がされない。

補足情報(FW/ツールのバージョンなど)

・Node.js
・Create React APP

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

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

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

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

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

thyda.eiqau

2019/11/11 13:57

・doshapeAの中のsetStateはどういった意図でアロー関数にしているのですか? ・constructorの中でthis.doshapeAを2回定義しているので、少なくともdoshapeBは期待通りに動かないと思いますが、こちらを修正するとどうなりますか?
kata.

2019/11/11 22:27

・doshapeAの中のsetStateはどういった意図でアロー関数にしているのですか? →thisの参照先が違う所を指していると思い、追加したものです。修正しました。 ・constructorの中でthis.doshapeAを2回定義しているので、少なくともdoshapeBは期待通りに動かないと思いますが、こちらを修正するとどうなりますか? →こちらは誤字でした。 修正した所、ボタンを押した時に違う図形が描写されるようになりました。 既にdataに格納したものについてはボタンを押しても変わらないようにしたいのですが、 今の状態ではボタンを押した時点で一緒に変わってしまうので、もう一度考えてみようと思います。
guest

回答1

0

ベストアンサー

thisの束縛について、bindを使うやり方とアロー関数を使うやり方のどちらを使ってもいいのですが、どちらかに統一しておいたほうが混乱しづらくてよいと思います。
bindを使うほうについては基本的な理解はされているようですので、アロー関数を使うやり方で次の通り例示します。

既にdataに格納したものについてはボタンを押しても変わらないようにしたいのですが、
今の状態ではボタンを押した時点で一緒に変わってしまう

こちらは、描画する際 (draw関数内) において、格納時に何が選ばれていたかではなくて、今何が選ばれているかで表示する図形を選択しているために起きています。

  • 格納時に、何が選ばれていたかが判別できる情報を併せて格納する
  • 描画時に、格納されている図形情報をもとに描画する

という処理が必要です。

jsx

1import React, { Component } from 'react'; 2import Rect from './Rect'; 3import './App.css'; 4 5class App extends Component{ 6 data = []; 7 8 msgStyle = { 9 fontSize: "24px", 10 color: "#900", 11 margin:"20px 0px", 12 padding: "5px", 13 } 14 15 btnStyle = { 16 fontsize: "20px", 17 padding: "10px 30px", 18 border: "border 1px solid", 19 margin: "0 20px 20px 0", 20 } 21 22 area = { 23 width: "500px", 24 height: "500px", 25 border: "1px solid blue" 26 } 27 28 shapes = { 29 A: <i class="fa fa-heart">A</i>, 30 B: <i class="fa fa-heart">B</i>, 31 } 32 33 constructor(props) { 34 super(props); 35 36 this.state = { 37 list: this.data, 38 currentShapeType: 'A', 39 }; 40 } 41 42 doAction(e) { 43 // this.data に保存するときに、どの図形を選んでいたのかがわかる情報をつける 44 this.data.push({ 45 x: e.pageX, 46 y: e.pageY, 47 shapeKey: this.state.currentShapeType, 48 }); 49 50 this.setState({list: this.data}); 51 } 52 53 changeShapeType(key) { 54 this.setState({currentShapeType: key}); 55 } 56 57 draw(d) { 58 let s = { 59 position: "absolute", 60 left: (d.x - 10) + "px", 61 top: (d.y - 10) + "px", 62 }; 63 64 // this.data に保存されている図形の種類にあわせて描画する 65 return ( 66 <div> 67 <div style={s}>{this.shapes[d.shapeKey]}</div> 68 </div> 69 ) 70 } 71 72 render(){ 73 return ( 74 <div> 75 <button style={this.btnStyle} onClick={() => this.changeShapeType('A')}>図形A</button> 76 <button style={this.btnStyle} onClick={() => this.changeShapeType('B')}>図形B</button> 77 <div style={this.area} onClick={() => this.doAction()}> 78 { 79 this.data.map(value => this.draw(value)) 80 } 81 </div> 82 </div> 83 ); 84 } 85} 86 87export default App;

投稿2019/11/12 05:04

thyda.eiqau

総合スコア2982

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

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

kata.

2019/11/12 22:14

thisの参照先について、bindかアロー関数のどちらかに統一した方が見やすいのは仰る通りです。 今後書く時に参考にさせて頂きます。 コードも見やすく、自分の意図したい事が再現できました。 自分で同じような機能を追加してみて定着させていこうと思います。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問