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

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

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

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

JavaScript

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

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

React.js

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

Q&A

解決済

2回答

2257閲覧

APIで取得したデータの一覧を.mapで表示させようとすると、エラーが発生する

wisheebell

総合スコア7

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

JavaScript

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

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

React.js

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

0グッド

0クリップ

投稿2019/08/23 17:05

編集2019/08/24 06:45

前提・実現したいこと

railsサーバーからapiでデータを取得し、Reactで一覧を表示する。

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

Uncaught TypeError: _this3.state.posts.map is not a function

該当のソースコード

Javascript

1import React, { Component } from 'react' 2import { withRouter } from 'react-router'; 3import axios from 'axios'; 4import Typography from '@material-ui/core/Typography' 5import Post from '../component/Post'; 6 7class Index extends Component { 8 constructor(props) { 9 super(props) 10 this.state = { 11 posts: [] 12 } 13 } 14 15 16 componentDidMount() { 17 axios 18 .get('https://6ccf1b5402214ffdb31120bbd0a35c58.vfs.cloud9.us-east-2.amazonaws.com/api/v1/posts') 19 .then((results) => { 20 console.log(results) 21 this.setState({ posts: results.data }) 22 }) 23 .catch((data) =>{ 24 console.log(data) 25 }) 26 } 27 28 render(){ 29 return( 30 <div> 31 {(() => { 32 if (this.state.posts != []) { 33 this.state.posts.map( post => { 34 return( 35 <Post title={post.created_at} name='testUser' title={post.title} content={post.content} /> 36 ) 37 }) 38 } else { 39 <Typography variant="h1" component="h2"> 40 まだなにも投稿されていません。 41 </Typography> 42 } 43 })()} 44 </div> 45 ); 46 } 47} 48 49export default Index; 50

試したこと

stack overflowにて似たような状況の質問を見つけたが、その質問の回答の通りに試しても正常に動作しなかった。

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

cloud9
React.js v16.8.6

###追記
回答のコメントより、改善したものを追記します。

Index

1import React, { Component } from 'react' 2import { withRouter } from 'react-router'; 3import axios from 'axios'; 4import Typography from '@material-ui/core/Typography' 5import Post from '../component/Post'; 6 7class Index extends Component { 8 constructor(props) { 9 super(props) 10 this.state = { 11 posts: [] 12 } 13 } 14 15 16 componentDidMount() { 17 axios 18 .get('https://6ccf1b5402214ffdb31120bbd0a35c58.vfs.cloud9.us-east-2.amazonaws.com/api/v1/posts') 19 .then((results) => { 20 console.log(results) 21 this.setState({ posts: results.data }) 22 }) 23 .catch((data) =>{ 24 console.log(data) 25 }) 26 } 27 28 render(){ 29 return( 30 <div> 31 {(() => { 32 if (this.state.posts.length > 0) { 33 return ( 34 this.state.posts.map( (post, i) => { 35 return( 36 <Post 37 key={i} 38 createdAt={post.created_at} 39 name='testUser' 40 title={post.title} 41 content={post.content} 42 /> 43 ) 44 }) 45 ) 46 } else { 47 return ( 48 <Typography variant="h6" component="h2"> 49 まだなにも投稿されていません。 50 </Typography> 51 ) 52 } 53 })()} 54 </div> 55 ); 56 } 57} 58 59export default Index;

Post

1import React, { Component } from 'react'; 2import { makeStyles, withStyles } from '@material-ui/core/styles'; 3import Card from '@material-ui/core/Card'; 4import CardActions from '@material-ui/core/CardActions'; 5import CardContent from '@material-ui/core/CardContent'; 6import Button from '@material-ui/core/Button'; 7import Typography from '@material-ui/core/Typography'; 8 9class Post extends Component { 10 render(){ 11 const classes = makeStyles({ 12 card: { 13 minWidth: 275, 14 }, 15 bullet: { 16 display: 'inline-block', 17 margin: '0 2px', 18 transform: 'scale(0.8)', 19 }, 20 title: { 21 fontSize: 14, 22 }, 23 pos: { 24 marginBottom: 12, 25 }, 26 }); 27 28 return ( 29 <Card className={classes.card}> 30 <CardContent> 31 <Typography className={classes.title} color="textSecondary" gutterBottom> 32 {this.props.createdAt} 33 </Typography> 34 <Typography variant="h5" component="h2"> 35 {this.props.name} 36 </Typography> 37 <Typography className={classes.pos} color="textSecondary"> 38 {this.props.title} 39 </Typography> 40 <Typography variant="body2" component="p"> 41 {this.props.content} 42 </Typography> 43 </CardContent> 44 <CardActions> 45 <Button size="small">Learn More...</Button> 46 </CardActions> 47 </Card> 48 ); 49 } 50} 51 52export default Post;

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

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

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

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

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

jun68ykt

2019/08/23 18:53

お手数ですが、axios でGETしているAPIのレスポンス もご質問に追記頂けますと、原因を特定しやすいかもしれません。
wisheebell

2019/08/24 02:47

書き込みありがとうございます。 レスポンスは以下のようになっています {data: {…}, status: 200, statusText: "", headers: {…}, config: {…}, …} config: {url: "https://6ccf1b5402214ffdb31120bbd0a35c58.vfs.cloud9.us-east-2.amazonaws.com/api/v1/posts", method: "get", headers: {…}, transformRequest: Array(1), transformResponse: Array(1), …} data: data: Array(1) 0: {id: 6, content: "hogehoge", created_at: "2019-08-23T15:18:02.644Z", updated_at: "2019-08-23T15:18:02.644Z", title: "sample"} length: 1 __proto__: Array(0) message: "loaded posts" status: "SUCCESS" __proto__: Object headers: {x-runtime: "0.024171", date: "Sat, 24 Aug 2019 02:45:17 GMT", referrer-policy: "strict-origin-when-cross-origin", x-permitted-cross-domain-policies: "none", etag: "W/"eeeef018be7df35fe8c9f5f2dbc842e9"", …} request: XMLHttpRequest {onreadystatechange: ƒ, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …} status: 200 statusText: "" __proto__: Object ステータスが200でdataの内容も問題ないので、おそらく正常に受け取れていると思われます。
jun68ykt

2019/08/24 04:55

レスポンスの追記、ありがとうございます。そうですね、レスポンスには問題ないようですね。他の部分に問題があると思われましたので、その点を修正したコードを回答しました。
guest

回答2

0

ベストアンサー

こんにちは

Indexコンポーネントについて、以下の4点
・if の条件を修正
・即時関数の return が欠けているので追加
・Post の prop title が重複しているので修正
・Post に key 追加
を修正して、下記のようにしてみるといかがでしょうか?

jsx

1import React, { Component } from 'react' 2import { withRouter } from 'react-router'; 3import axios from 'axios'; 4import Typography from '@material-ui/core/Typography' 5import Post from '../component/Post'; 6 7class Index extends Component { 8 constructor(props) { 9 super(props) 10 this.state = { 11 posts: [] 12 } 13 } 14 15 16 componentDidMount() { 17 axios 18 .get('https://6ccf1b5402214ffdb31120bbd0a35c58.vfs.cloud9.us-east-2.amazonaws.com/api/v1/posts') 19 .then((results) => { 20 console.log(results) 21 this.setState({ posts: results.data }) 22 }) 23 .catch((data) =>{ 24 console.log(data) 25 }) 26 } 27 28 render(){ 29 return( 30 <div> 31 {(() => { 32 if (this.state.posts.length > 0) { 33 return ( 34 this.state.posts.map( (post, i) => { 35 return( 36 <Post 37 key={i} 38 createdAt={post.created_at} 39 name='testUser' 40 title={post.title} 41 content={post.content} 42 /> 43 ) 44 }) 45 ) 46 } else { 47 return ( 48 <Typography variant="h1" component="h2"> 49 まだなにも投稿されていません。 50 </Typography> 51 ) 52 } 53 })()} 54 </div> 55 ); 56 } 57} 58 59export default Index; 60

参考までに、上記の修正を確認するためのコードを、以下に作成しています。

以下は上記のレポジトリの説明です。

  • 最初のコミット での Index は、ご質問にあるコードをコピペし、axios で GET するURLだけ、以下

https://demo2746340.mockable.io/q207924/posts
に修正しています。

  • 次のコミット、 以下の4点を修正 では、上記に挙げた4点の修正を行っています。

以下の手順で動作確認できます。

上記によって、以下のように表示されると思います。

イメージ説明

以下3点は補足です。

(1) 最初のコミット で yarn start させると確かにエラーにはなりますが、ご質問にある、
Uncaught TypeError: _this3.state.posts.map is not a function
というエラーは再現しませんでした。

(2) posts が空の配列である場合の「まだなにも投稿されていません。」のような表示をエンプティステートといいますが、エンプティステートを返すべきかどうかの判定をrenderの冒頭でやってしまって、該当していたら、早々とreturn させるという手も、個人的にはよく使います。その場合は以下のようにします。

(3) 上記の(2) の他に、エンプティステートを表示すべき場合と、そうでない場合の切り分けに、三項演算子を使うこともできます。

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

投稿2019/08/24 04:46

jun68ykt

総合スコア9058

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

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

wisheebell

2019/08/24 05:41

細かい説明ありがとうございます エンプティステートの扱いはとても参考になります 実際に確認してみたところ、 エラー無く表示されるようにはなったのですが、postsに要素が格納されていても「まだなにも投稿されていません」と表示されてしまいます。なにか心当たりなどありますか?
jun68ykt

2019/08/24 05:48

コメントありがとうございます。 > エラー無く表示されるようにはなった とのことで、(とりあえずは)よかったです。 次に、 > postsに要素が格納されていても「まだなにも投稿されていません」と表示されてしまいます。 についてですが、その、 > 「まだなにも投稿されていません」と表示されてしまいます。 というのは、より詳しくいうと、  レスポンスの配列に要素がある場合でも、this.state.postsの内容が表示される前に、  一瞬、「まだなにも投稿されていません」が見えてしまう。 ということでしょうか?
jun68ykt

2019/08/24 06:00

もし、上記である場合、それは書いたコードの通りの表示です。 というのは、現状のコードだと、axios によるAPIリクエストが返ってくるまでの間は、this.state.posts はコンストラクタで設定した空の配列のままなので、「まだなにも投稿されていません」が表示されます。 もし上記ではない場合、すなわち  APIのレスポンスとしては空ではない配列が返ってきているのに、「まだなにも投稿されていません」が表示されたまま である場合は、まだどこかがおかしいです。
wisheebell

2019/08/24 06:02

一瞬表示されるわけではなく、 「まだなにも投稿されていません」以外に全く要素が表示されていない状態です。
jun68ykt

2019/08/24 06:06

なるほどです。それでは、修正後の Index コンポーネントのソースコードをご質問のほうに、追記いただけますでしょうか? もし Post コンポーネントも怪しい所があるかもしれないのでしたら、Post のほうもコードを追記頂ければと思います。
wisheebell

2019/08/24 06:46

実際に修正したIndex.jsxとPost.jsxのコードを追記しました
jun68ykt

2019/08/24 07:56 編集

追記ありがとうございます。 拝見しましたが、どこが原因なのか分からず、これでなぜうまくいかないのだろう・・?という感じです。 そこで試してみて欲しいのですが、修正後の以下の部分 render(){   return(    <div> で、 render() { と return( の間に、this.state.posts を console に出すように、以下の1行を追加してみて頂けますでしょうか? render(){   console.log(`render: ${JSON.stringify(this.state.posts)}`); // この行を追加   return(    <div> ちなみに私のほうで作成したコードに上記を追加すると、追加した consol.log によって以下のように出力されます。 https://git.io/fjN9I 2度目の render 時には、 this.state.posts に要素が入っているのを確認できます。 wisheebellさんのコードではいかがでしょうか?
jun68ykt

2019/08/24 08:44

もう一点、これが原因ではと思うところがあります。 wisheebellさんのコードで、GET しているAPI のレスポンスは、以下のような形式のJSONを返しているのではないでしょうか? { "data": [ { ・・・}, {・・・}, {・・・} ] } つまり、全体はオブジェクトで、その中に data というプロパティがあり、そのdata プロパティの値が配列になっているというものです。 上記であるならば this.setState({ posts: results.data }) を、以下のように修正する必要があります。 this.setState({ posts: results.data.data }) 上記を試してみて頂ければと思います。
jun68ykt

2019/08/24 08:52

原因は、おそらく上記ではないかなと思っています。 レスポンスが { "data": [ { ・・・}, {・・・}, {・・・} ] } というもので、 this.setState({ posts: results.data }) とすると、同じ data というプロパティを使っていても、 results.data の data は axios が作るもので、レスポンスの中の data プロパティではなく、レスポンス全体を参照していますので、 this.setState({ posts: results.data }) とすると、this.state.posts にはレスポンス全体のオブジェクトが入ります。そのためオブジェクトには map というメソッドはないので、ご質問の冒頭にある Uncaught TypeError: _this3.state.posts.map is not a function というエラーになります。 レスポンスのプロパティに data というプロパティを使うと混乱の元だったりもするので、data ではなく たとえば { "posts": [ { ・・・}, {・・・}, {・・・} ] } としておいて、 this.setState({ posts: results.data.posts }) とするのもよいかもしれません。
jun68ykt

2019/08/24 09:00

ちなみにご質問に追記いただきました Post のほうは特に問題なく、私の回答で作成したコードの Post にそのままコピペしても意図通り Material でデザインされたPostコンポーネントが表示されました。
wisheebell

2019/08/24 09:23

上記の通りthis.setState({ posts: results.data.data })と修正したところ、正常に動作しました! わかりにくい質問でしたが、根気よくお付き合いいただきありがとうございます!
jun68ykt

2019/08/24 09:27

どういたしまして!解決したようで、よかったです ????
guest

0

Uncaught TypeError: _this3.state.posts.map は関数ではありません

投稿2019/08/23 22:34

y_waiwai

総合スコア87719

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問