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

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

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

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

React.js

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

Q&A

解決済

1回答

698閲覧

render時にstate.mapでエラーが出てしまう

hfidk

総合スコア18

JavaScript

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

React.js

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

0グッド

0クリップ

投稿2019/01/14 23:58

stateにタグを配列形式で追加した後、map関数でrenderしようとしました

json内のデータをもとに配列にタグを追加しようとしたところ、エラーが出てつまりました

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

TypeError: this.state.drawnTag.map is not a function

該当のソースコード

state = { drawnTag: [] } getInfo = () =>{ var ref_Data = require('../users_mirror.json'); var components_Data = ref_Data.users[this.props.account_Name].components; Object.keys(components_Data).forEach(function(key){ if(components_Data[key]){ this.setState({ drawnTag: this.state.drawnTag.push(<Comp />) }); } }.bind(this)); console.log(this.state.drawnTag); } componentWillMount(){ this.getInfo(); console.log(this.state.drawnTag); } render(){ return( <div> { this.state.drawnTag.map((item, i) => <React.Fragment key={i}><div>{item}</div></React.Fragment>) } </div> );

配列内に収めたタグを順番にrenderして出力したいです、なにが間違っているのでしょうか

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんにちは

setState している箇所を、以下のように修正してみると、いかがでしょうか?

修正前:

javascript

1this.setState({ 2 drawnTag: this.state.drawnTag.push(<Comp />) 3});

修正後:

javascript

1this.setState({ 2 drawnTag: [...this.state.drawnTag, <Comp />] 3});

修正前の何が問題かというと、push の戻り値は、要素追加後の配列ではない点です。 
Array.prototype.push() の戻り値のところに以下の記載があります。

戻り値

メソッドが呼び出されたオブジェクトの新しい length プロパティ。

以上参考になれば幸いです。

追記1

componentWillMount は React 16.3から非推奨メソッドになったので、v16.3以降を使用の際は、替わりに componentDidMount を使うことをお勧めします。

追記2

Clockrender で発生している "Nothing was returned from render." というエラーは、以下の修正でとりあえず発生しなくなると思います。

修正前:

jsx

1 render() { //デジタル時計のデザインをpropsで管理できるようにした."view=''"で"vertical"で水平に"horizontal"で縦並びに 2 if (this.props.view === "horizontal") { 3 return ( 4 <div 5 style={{}} 6 className="clock_flame" 7 > 8 <span id="clock_hour"> 9 {this.state.hours} 10 </span> 11 <span id="clock_minute"> 12 {this.state.minutes} 13 </span> 14 </div> 15 ) 16 } else if (this.props.view === "vertical") { 17 return ( 18 <div 19 style={{}} 20 className="clock_flame_vertical" 21 > 22 <div id="clock_hour_vertical" className="vertical"> 23 {this.state.hours} 24 </div> 25 <div id="clock_minute_vertical" className="vertical"> 26 {this.state.minutes} 27 </div> 28 </div> 29 ); 30 } 31 }

 


修正方法ですが、render() の終わりの } の直前に

javascript

1return <div>{this.state.hours}{this.state.minutes}</div>;

を追加して、 以下のようにします。 

修正後:

jsx

1 render() { //デジタル時計のデザインをpropsで管理できるようにした."view=''"で"vertical"で水平に"horizontal"で縦並びに 2 if (this.props.view === "horizontal") { 3 return ( 4 <div 5 style={{}} 6 className="clock_flame" 7 > 8 <span id="clock_hour"> 9 {this.state.hours} 10 </span> 11 <span id="clock_minute"> 12 {this.state.minutes} 13 </span> 14 </div> 15 ) 16 } else if (this.props.view === "vertical") { 17 return ( 18 <div 19 style={{}} 20 className="clock_flame_vertical" 21 > 22 <div id="clock_hour_vertical" className="vertical"> 23 {this.state.hours} 24 </div> 25 <div id="clock_minute_vertical" className="vertical"> 26 {this.state.minutes} 27 </div> 28 </div> 29 ); 30 } 31 32 return <div>{this.state.hours}{this.state.minutes}</div>; // この行を追加 33 }

このように修正すると、Clock の props view が与えられなかったり、与えられてもhorizontalまたはverticalのいずれでもない場合に、とりあえず{this.state.hours}{this.state.minutes}を並べて、 classNameやstyleを指定しない単なる <div>で囲んだものを返すようになり、Clock を使う側で <Clock /> のように viewを指定し忘れても、
"Nothing was returned from render."
は出なくなると思います。

その上で Clock を使う側では <Clock view="horizontal" /> または <Clock view="vertical" /> というように、適切な値のviewをpropsで渡すようにすればよいかと思います。逆に、表示したときにスタイルがあたらずに時と分が表示されたら、それは viewの値が適切にprops経由で渡せていないと気がつくことができます。

追記3

ご質問にあるコードの以下の部分で、 forEach の中で setState しているのが怪しいです。

修正前:

getInfo = () =>{ var ref_Data = require('../users_mirror.json'); var components_Data = ref_Data.users[this.props.account_Name].components; Object.keys(components_Data).forEach(function(key){ if(components_Data[key]){ this.setState({ drawnTag: this.state.drawnTag.push(<Comp />) }); } }.bind(this)); }

これだと、components_Data に複数タグ分のデータがあったときに、setStateが複数回呼ばれてしまいます。ですので、上記を以下のように修正してみるといかがでしょうか? (こんどはpushで大丈夫です。)

修正後:

javascript

1 getInfo = () =>{ 2 var ref_Data = require('../users_mirror.json'); 3 var components_Data = ref_Data.users[this.props.account_Name].components; 4 var drawnTag = []; 5 Object.keys(components_Data).forEach(function(key){ 6 if(components_Data[key]){ 7 drawnTag.push(<Comp />); 8 } 9 }); 10 this.setState({ drawnTag }); 11 };

すなわち、 forEach のループに入る前に、 drawnTag というローカル変数で空配列の配列を用意しておき、 forEach のループでこの配列に <Comp /> を追加していきます。そして、forEachを抜けた後に、
this.setState({ drawnTag });
で、state に反映させるようにします。こうすることでgetInfoが呼ばれたときに setState が1回だけ実行されるようになります。

上記の趣旨の修正をお手元のコードにしてみると意図通り動くかもしれません。

それと、 console.log(this.state.drawnTag); というデバッグログは、以下のように render の中で行うのがよいです。一度、他の箇所にあるconsole.log(this.state.drawnTag); をコメントアウトして、以下の箇所にだけ入れてみることをお勧めします。

javascript

1 render() { 2 console.log(this.state.drawnTag); 3 return ( 4 <div> 5 {this.state.drawnTag.map((item, i) => 6 <React.Fragment key={i}> 7 <div>{item}</div> 8 </React.Fragment>) 9 } 10 </div> 11 ); 12 }

追記4

コメントから頂きました、

hfidk 2019/01/17 18:13

余計な質問すいません,追加するタグの名前をオブジェクトのキー名にすることってできませんか?

とのご質問への回答です。これは以下の質問と同じ要望かと思います。

上記への回答、

にある

So you simply need to find a way to map between the string "Home" and the component class Home. A simple object will work as a basic registry, and you can build from there if you need more features.

javascript

1var components = { 2 "Home": Home, 3 "Other": OtherComponent 4}; 5 6var Component = components[this.props.template];

を参考にすればよいです。以下簡単なサンプルです。

3つのタグコンポーネント FooTag, BarTag, BazTag があります。App のprops tag"foo","bar","baz" のいずれかが渡ってくる想定で、これらの文字列から表示対象のタグコンポーネントを変数 Tag に入れて、これをJSX形式で書いて表示するという例です。

jsx

1class FooTag extends React.Component { 2 render() { 3 return <span>This is a FooTag.</span>; 4 } 5} 6 7class BarTag extends React.Component { 8 render() { 9 return <span>This is a BarTag.</span>; 10 } 11} 12 13class BazTag extends React.Component { 14 render() { 15 return <span>This is a BazTag.</span>; 16 } 17} 18 19const tagComponents = { 20 foo: FooTag, 21 bar: BarTag, 22 baz: BazTag, 23}; 24 25class App extends React.Component { 26 render() { 27 const Tag = tagComponents[this.props.tag] || FooTag; 28 return ( 29 <div className="app"> 30 <Tag /> 31 </div> 32 ); 33 } 34} 35 36ReactDOM.render(<App tag="bar" />, document.querySelector("#app"));

キーとなる文字列とコンポーネントをマップするオブジェクト tagComponents を作るというのが、ひと手間かかりますが、いったんルールを決めて作ってしまえば、追加していくのはそれほど大変ではありません。私自身、時々、業務でも使う小技です。

肝は、

javascript

1const Tag = tagComponents[this.props.tag] || FooTag;

と、Tagのような、大文字で始まる変数名に代入することです。こうすると <Tag /> と書けますが、これを

javascript

1const tag = tagComponents[this.props.tag] || FooTag;

として <tag /> と書いても、意図したようには表示されません。

投稿2019/01/15 01:54

編集2019/01/18 06:25
jun68ykt

総合スコア9058

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

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

hfidk

2019/01/15 13:58

componentcycleの説明も含め解凍ありがとうございます。 Clock(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null. というエラーが出るのですが、中身ははいってるはずなのにどうしたものでしょうか
jun68ykt

2019/01/15 14:41 編集

違うエラーが出るようになったわけですね。コンポーネント <Comp /> のほうで、 render()メソッドが何も返していない可能性があるので、念のため、Comp コンポーネントのソースもご質問にコピペで追記頂けますでしょうか? ちなみに、"Nothing was returned from render." で検索したら以下の投稿をみつけました。 https://stackoverflow.com/questions/46741247/ 上記の回答にある、エラーになってしまう方の書き方をしていないか、確認されるのもよいかもしれません。
hfidk

2019/01/15 18:56

``` import React, {Component} from "react"; import './Clock.css'; //var now = new Date(); class Clock extends Component { state = { hours: "", minutes: "" }; start () { this.setState({ hours:(new Date()).getHours(), //分 minutes:(new Date()).getMinutes() //秒 }); //1桁で表される時刻の先頭に0を追加して見栄えを良くした if(this.state.hours <= 9) { this.setState({ hours:"0" + (new Date()).getHours() }); } if(this.state.minutes <= 9) { this.setState({ minutes:"0" + (new Date()).getMinutes() }); } } componentDidMount() { this.interval = setInterval(() => this.start(), 1000); //定期的にstate内の時間を更新 } render() { //デジタル時計のデザインをpropsで管理できるようにした."view=''"で"vertical"で水平に"horizontal"で縦並びに if(this.props.view === "horizontal"){ return( <div style={{}} className="clock_flame" > <span id="clock_hour"> {this.state.hours} </span> <span id="clock_minute"> {this.state.minutes} </span> </div> )} else if(this.props.view === "vertical"){ return( <div style={{}} className="clock_flame_vertical" > <div id="clock_hour_vertical" className="vertical"> {this.state.hours} </div> <div id="clock_minute_vertical" className="vertical"> {this.state.minutes} </div> </div> ); } } } export default Clock; ``` です。
jun68ykt

2019/01/16 02:08

回答のほうに追記2 として修正方法を書きました。
hfidk

2019/01/16 17:31

修正も含めありがとうございます.最後に一ついいですか? setStateでdrawnTagの配列にタグを挿入する時ですが,そのあとrenderで表示させようとしても一つしか表示されません.for文のミスかと思い確実にいくつか配列に挿入されるようにしても同じくです.なにか思い当たるようなミスってありませんか? 付き当ってくださりありがとうございます
jun68ykt

2019/01/17 02:19

確認ですが、以下のエラーは出なくなったでしょうか? Clock(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null. それと、「そのあとrenderで表示させようとしても一つしか表示されません.」について、回答のほうに追記3 として、ここが怪しいと思った箇所とその修正方法を書きましたので、これと同様の修正をお手元にコードで試してみて頂ければと思います。
hfidk

2019/01/17 08:54

ありがとうございます,解決しました.丁寧な解説とても助かりました.めちゃくちゃ感謝します!!!
jun68ykt

2019/01/17 09:04

解決したとのことで、よかったです????
hfidk

2019/01/17 09:13

余計な質問すいません,追加するタグの名前をオブジェクトのキー名にすることってできませんか?{}で囲んで<{key} />でいいのかとおもったのですができず...なぜ不可能なのかも腑に落ちません 解説,心から感謝します!!
jun68ykt

2019/01/17 10:13

> 追加するタグの名前をオブジェクトのキー名にすることってできませんか? の件ですが、そのご要望ズバリそのままのことはできませんが、近いことはできます。サンプルを回答のほうに追記4として書きましたので、参考にしてみてください。 すみませんが、さらなる追加のご質問は、新しい投稿にして頂けますと幸いです。
hfidk

2019/01/17 12:21

ありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問