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

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

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

Next.jsは、Reactを用いたサーバサイドレンダリングなどを行う軽量なフレームワークです。Zeit社が開発しており、nextコマンドでプロジェクトを作成することにより、開発環境整備が整った環境が即時に作成できます。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

Q&A

解決済

1回答

2394閲覧

propsの配列データの受け渡しがうまくいかない

aren3

総合スコア9

Next.js

Next.jsは、Reactを用いたサーバサイドレンダリングなどを行う軽量なフレームワークです。Zeit社が開発しており、nextコマンドでプロジェクトを作成することにより、開発環境整備が整った環境が即時に作成できます。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

0グッド

0クリップ

投稿2022/01/02 11:55

編集2022/01/02 12:52
(src/types/spotData.tsx) export type spotData = { spot: Array<spotData>; };
(src/pages/index.tsx) const Index: NextPage = () => { const [spot, setSpot] = useState<spotData[]>([]); const fetchSpot = useCallback(async () => { const data: string[] | undefined = await getSpots(); setSpot(data || []); }, []); useEffect(() => { fetchSpot(); }, [fetchSpot]); return ( <UserLayout> <SpotCard spot={spot} /> // 上記の行でエラーメッセージが出ています </UserLayout> ); }; export default Index;
(src/components/Spot/SpotCard/index.tsx) export const SpotCard: VFC<spotData> = (props) => { console.log(props); const { spot } = props; const property = { imageUrl: 'spot-pic.jpeg', imageAlt: 'props.image_url', heart: '12', }; return ( <Flex bg={useColorModeValue('#F9FAFB', 'gray.600')} p={50} w='full' alignItems='center' justifyContent='center' > <Box bg={useColorModeValue('white', 'gray.800')} maxW='sm' borderWidth='1px' rounded='lg' shadow='lg' > <div className='relative text-center text-xs md:w-30 h-50'> <Image src={property.imageUrl} alt={property.imageAlt} roundedTop='lg' /> <div className='absolute flex flex-col text-white text-center top-0 left-0 '> <PrefectureButton /> <SystemButton /> </div> </div> <Box p='6' mt='3'> <Box d='flex'> <Box color='blsck.500' fontWeight='semibold' letterSpacing='wide' fontSize='md' textTransform='uppercase' ml='2' > <div className='flex mb-2 mr-2'> <Image src='/map-marker-icon.png' alt='地図マーカーアイコン' /> <div className='mt-1 ml-1'> {name}</div>                                                         // 上記の行でエラーメッセージが出ています </div> </Box> </Box> <Box mt='10' mb='5' as='h4' fontSize='lg' lineHeight='tight'> <div className='text-md'>{title}</div>                                                // 上記の行でエラーメッセージが出ています </Box> <Box> <div className='flex justify-between mb-2 mr-2'> <div className='flex'> <Image borderRadius='full' boxSize='50px' src='/admin-test-pic.jpg' alt='props.image_url' /> <div className='ml-2 mt-4'>{area}</div>                                              // 上記の行でエラーメッセージが出ています </div> <Box as='span' color='black.600' fontSize='md'></Box> <div className='flex text-right mt-3'> <div className='mt-1'> <Image src='/heart-line.png' width={5} height={5} alt='ハートアイコン' /> </div> <div className='text-lg ml-1'>{property.heart}</div> </div> </div> </Box> </Box> </Box> </Flex> ); };

状況

Next.js(Typescript)とSupabaseで開発しており、supabaseで取得したデータを(src/pages/index.tsx)ページからSpotCardコンポーネントのページにpropsで渡しています。
SpotCardコンポーネントには取得したデータが入っているのはログを出して確認済みです。

エラー内容

①(src/pages/index.tsx)の<SpotCard spot={spot} />の箇所で「型 '{ spot: spotData[]; }' を型 'IntrinsicAttributes & spotData' に割り当てることはできません。プロパティ 'spot' は型 'IntrinsicAttributes & spotData' に存在しません。」とエラーが出ています。

②(src/components/Spot/SpotCard/index.tsx)の箇所ではpropsで渡している中のspotsに入っている。name、title,areaをそれぞれ表示させたいのですが、それぞれ名前がありませんとエラーが出ており、それぞれの書き方と対応方法を教えて頂けたら幸いです。宜しくお願い致します。

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

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

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

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

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

hoshi-takanori

2022/01/02 23:06

spotData は再帰的な型になってて、たとえばこんなのが入りますが、実際のデータは何も入らないような…。 const spot: spotData = { spot: [{ spot: [] }, { spot: [{ spot: [] }] }] }; あと、型名の最初の文字は SpotData のように大文字にするのが一般的かと。
aren3

2022/01/03 02:18 編集

ご回答ありがとうございます! 確かに再帰的な型になっていました。型名の大文字にするご指摘もありがとうございます。 ここはspot: string;のような書き換えでよかったでしょうか? 具体的にはどのようにコードを修正していけばいいかご教授いただけますでしょうか?
hoshi-takanori

2022/01/03 02:16

spot が具体的にどのようなデータかによります。
aren3

2022/01/03 02:31

spotにはArrayでデータが渡ってきており、そのArrayそれぞれに20のカラムが入っています。 今回はそのデータの中からid, name, title, areaという項目のみ使用したいと考えています。
hoshi-takanori

2022/01/03 05:23 編集

それって全然具体的じゃないんですが、spot の中身は例えばこんな感じですが? [   {     "id": 1,     "name": "札幌時計台",     "title": "旧札幌農学校演武場",     "area": "北海道"   },   {     "id": 2,     "name": "はりまや橋",     "title": "♪土佐の高知のはりまや橋で,坊さんかんざし買うを見た",     "area": "高知県"   },   {     "id": 3,     "name": "オランダ坂",     "title": "長崎市東山手の旧居留地時代につくられた石畳の坂道・石段",     "area": "長崎県"   } ]
aren3

2022/01/03 05:29

そうです!! 綺麗にコードをまとめて頂きありがとうございます!
hoshi-takanori

2022/01/04 00:50

うーん、よくみたら SpotCard コンポーネントは一つの場所しか表示するようになってないですね。確認ですが、やりたいことは、リンク先のように複数の場所をカードレイアウトで表示することですか? https://www.club-t.com/sp/kanko/ あと、すごい失礼な質問で申し訳ないんですが、もしかして配列とオブジェクトの区別がついてなかったりします? (PHP 書いてる人にありがちかも…。)
aren3

2022/01/04 00:58

そうですね! リンク先のようにSpotCardがPC版では縦3列✖︎横3列で並ぶイメージです。 そこは大丈夫かと自分では思っていたのですが、どのあたりでそれを感じられたでしょうか?
guest

回答1

0

ベストアンサー

例えば API からこんな感じの JSON が返ってくるとして、

json

1{ 2 "spot": [ 3 { 4 "id": 1, 5 "name": "札幌時計台", 6 "title": "旧札幌農学校演武場", 7 "area": "北海道" 8 }, 9 { 10 "id": 2, 11 "name": "はりまや橋", 12 "title": "♪土佐の高知のはりまや橋で,坊さんかんざし買うを見た", 13 "area": "高知県" 14 }, 15 { 16 "id": 3, 17 "name": "オランダ坂", 18 "title": "長崎市東山手の旧居留地時代につくられた石畳の坂道・石段", 19 "area": "長崎県" 20 } 21 ] 22}

これをカードレイアウトで表示したいってことですよね。


まず、データの型付けですが、いちばん基本的なものは一つの場所 (スポット) を表すものでしょうね。これを表すオブジェクト型を次のように定義します。

TypeScript

1type SpotData = { 2 id: number, 3 name: string, 4 title: string, 5 area: string 6};

一つの場所を表す変数は次のように単数形にします。

TypeScript

1const spot: SpotData = { 2 id: 1, 3 name: "札幌時計台", 4 title: "旧札幌農学校演武場", 5 area: "北海道" 6};

また、複数の場所が配列になる場合は、spots のように複数形にするか、spotArray や spotList のような名前にします。

TypeScript

1const spots: SpotData[] = [ 2 { 3 id: 1, 4 name: "札幌時計台", 5 title: "旧札幌農学校演武場", 6 area: "北海道" 7 }, 8 { 9 id: 2, 10 name: "はりまや橋", 11 title: "♪土佐の高知のはりまや橋で,坊さんかんざし買うを見た", 12 area: "高知県" 13 }, 14 { 15 id: 3, 16 name: "オランダ坂", 17 title: "長崎市東山手の旧居留地時代につくられた石畳の坂道・石段", 18 area: "長崎県" 19 } 20];

また、API の結果を表す型が欲しければこんな感じで定義すると良いでしょう。

TypeScript

1type SpotResult = { 2 spot: SpotData[] 3};

(場所の配列に対応するキーが spot という単数形なのはいけてないですが、API がそうなってるなら仕方ありませんね。)


React のコンポーネントを定義する場合も、コンポーネントやそのプロパティの名前が単数か複数かを意識すると良いでしょう。例えば一つの場所を表示する一つのカードは次のようになるでしょう。

tsx

1type SpotCardProps = { 2 spot: SpotData 3}; 4 5export const SpotCard: VFC<SpotCardProps> = (props) => { 6 return ( 7 <div className='card'> 8 <div className='card-name'>{props.spot.name}</div> 9 <div className='card-title'>{props.spot.title}</div> 10 <div className='card-area'>{props.spot.area}</div> 11 </div> 12 ); 13};

試しにこれを表示するテスト用のコンポーネントはこんな感じです。

tsx

1export const SpotCardTest: VFC = () => { 2 const spot: SpotData = { 3 id: 1, 4 name: "札幌時計台", 5 title: "旧札幌農学校演武場", 6 area: "北海道" 7 }; 8 9 return (<SpotCard spot={spot} />); 10};

ここで、<SpotCard spot={spot} /> とすると SpotCard コンポーネントの props 引数には { spot: { id: 1, name: '札幌時計台', ... } } という入れ子になったオブジェクトが渡ることに注意しましょう。

上では SpotCard コンポーネントの引数の型を SpotCardProps という名前で定義しましたが、このような単純なものならわざわざ型を定義しなくても構いません。

tsx

1export const SpotCard: VFC<{ spot: SpotData }> = (props) => { 2 // 略 3}

また、引数を受け取る側は props という一つの引数のすべてのプロパティをまとめて受け取る代わりに、オブジェクトの分割代入を使って書くこともできます。こうすると、例えば name にアクセスするには props.spot.name の代わりに spot.name と書くことができます。

tsx

1export const SpotCard: VFC<{ spot: SpotData }> = ({ spot }) => { 2 return ( 3 <div className='card'> 4 <div className='card-name'>{spot.name}</div> 5 <div className='card-title'>{spot.title}</div> 6 <div className='card-area'>{spot.area}</div> 7 </div> 8 ); 9};

そして、SpotCard を使う側では、複数の場所のデータを配列で持って、それらを map を使って表示することになるでしょうね。(SpotData の配列を表す変数名は複数形の spots、一つの SpotData は spot という単数形なことに注意。紛らわしければ spots の代わりに spotArray とかにしても良いでしょう。)

tsx

1const Index: NextPage = () => { 2 const [spots, setSpots] = useState<SpotData[]>([]); 3 4 // spots を取得するコードは省略 5 6 return ( 7 <UserLayout> 8 {spots.map(spot => <SpotCard key={spot.id} spot={spot} />)} 9 </UserLayout> 10 ); 11};

投稿2022/01/04 09:58

編集2022/01/04 10:34
hoshi-takanori

総合スコア7895

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

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

aren3

2022/01/05 05:59

ご丁寧に細かく解説付きで教えて頂きありがとうございました! 意図した挙動まで実装ができましたので、助かりました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問