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

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

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

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

React.js

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

Q&A

解決済

1回答

2644閲覧

Next.jsにおける外部APIの使用

HelloQ

総合スコア81

Next.js

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

React.js

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

0グッド

0クリップ

投稿2021/08/14 04:42

編集2021/08/14 06:39

やりたいこと

Next.jsでブログを作成したいです.
GitHub APIを使用して外部から記事の情報を取得してソートしたいのですが、上手く行かないので、どなたかご教授頂けると幸いです.

ソースコード

GitHub

lib/posts.js

javascript

1export async function getSortedPostsData() { 2 // Get file names under /posts 3 // const fileNames = fs.readdirSync(postsDirectory) 4 const repoUrl = "https://api.github.com/repos/satorun082/article/contents" 5 const response = await fetch(repoUrl) 6 const files = await response.json() 7 const fileNames = files.map(file => file.name) 8 9 const allPostsData = fileNames.map(async (fileName) => { 10 // Remove ".md" from file name to get id 11 const id = fileName.replace(/.md$/, '') 12 13 // Read markdown file as string 14 const repoUrl_tmp = `https://api.github.com/repos/satorun082/article/contents/${id}.md` 15 const response_tmp = await fetch(repoUrl_tmp) 16 const file_tmp = await response_tmp.json() 17 const fileContents = base64.decode(file_tmp.content) 18 19 // Use gray-matter to parse the post metadata section 20 const matterResult = matter(fileContents) 21 22 // Combine the data with the id 23 return { 24 id, 25 ...matterResult.data 26 } 27 }) 28 // Sort posts by date 29 return await allPostsData.sort(({ date: a }, { date: b }) => { 30 if (a < b) { 31 return 1 32 } else if (a > b) { 33 return -1 34 } else { 35 return 0 36 } 37 }) 38}

index.tsx

import { GetStaticProps } from 'next' import Head from 'next/head' import Layout, { siteTitle } from '../components/layout' import utilStyles from '../styles/utils.module.css' import { getSortedPostsData } from '../lib/posts' import Link from 'next/link' import Date from '../components/date' export const getStaticProps: GetStaticProps = async() => { const allPostsData = await getSortedPostsData() return { props: { allPostsData } } } type Props = { allPostsData: { id: string title: string date: string }[] } export default function Home({ allPostsData }: Props) { return ( <Layout home> <Head> <title>{siteTitle}</title> </Head> <section className={utilStyles.headingMd}> <p>Im nakadats and Im learning English to make my brondy girl friends</p> <p> (This is a sample website - you’ll be building a site like this on{' '} <a href="https://nextjs.org/learn">our Next.js tutorial</a>.) </p> </section> <section className={`${utilStyles.headingMd} ${utilStyles.padding1px}`}> <h2 className={utilStyles.headingLg}>Blog</h2> <ul className={utilStyles.list}> {allPostsData.map(({ id, date, title }) => ( <li className={utilStyles.listItem} key={id}> <Link href={`/${id}`}> <a>{title}</a> </Link> <br /> <small className={utilStyles.lightText}> <Date dateString={date} /> </small> </li> ))} </ul> </section> </Layout> ) }

エラー内容

error

1Server Error 2Error: Error serializing `.allPostsData[0]` returned from `getStaticProps` in "/". 3Reason: `object` ("[object Promise]") cannot be serialized as JSON. Please only return JSON serializable data types. 4 5This error happened while generating the page. Any console logs will be displayed in the terminal window. 6Call Stack 7isSerializable 8file:///mnt/c/Users/minolab/Desktop/nextjs-blog/node_modules/next/dist/lib/is-serializable-props.js (64:15) 9<unknown> 10file:///mnt/c/Users/minolab/Desktop/nextjs-blog/node_modules/next/dist/lib/is-serializable-props.js (56:24) 11Array.every 12<anonymous> 13isSerializable 14file:///mnt/c/Users/minolab/Desktop/nextjs-blog/node_modules/next/dist/lib/is-serializable-props.js (54:23) 15<unknown> 16file:///mnt/c/Users/minolab/Desktop/nextjs-blog/node_modules/next/dist/lib/is-serializable-props.js (46:66) 17Array.every 18<anonymous> 19isSerializable 20file:///mnt/c/Users/minolab/Desktop/nextjs-blog/node_modules/next/dist/lib/is-serializable-props.js (43:39) 21Object.isSerializableProps 22file:///mnt/c/Users/minolab/Desktop/nextjs-blog/node_modules/next/dist/lib/is-serializable-props.js (66:12) 23Object.renderToHTML 24file:///mnt/c/Users/minolab/Desktop/nextjs-blog/node_modules/next/dist/server/render.js (430:97) 25runMicrotasks 26<anonymous>

参考サイト

日本一わかりやすいNext.js入門 番外編!外部APIからデータを取得・表示しよう

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

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

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

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

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

guest

回答1

0

ベストアンサー

こちらの記述ではawaitを付けているのに、

const repoUrl = "https://api.github.com/repos/satorun082/article/contents" const response = await fetch(repoUrl) const files = await response.json()

何故こちらでは外してしまったんですか?

const repoUrl_tmp = `https://api.github.com/repos/satorun082/article/contents/${id}.md` const response_tmp = fetch(repoUrl_tmp) const file_tmp = response_tmp.json()

あまり理解せずに記述しているのだと思いますが、fetch(*)promiseを返すので*.json()というメソッドは存在しません。awaitなどでpromiseが解決されてはじめて、.json()でresponseからJSONデータを取り出すことが出来ます。

おそらくawaitを記述したらエラーが出たので外したのでしょうが、mapにもasyncを設定することができます。

const allPostsData = fileNames.map(async (fileName) => { ... const hoge = await fuga() ... })

追記

const allPostsData = fileNames.map(async (fileName) => {...})のpromiseが解決できていません。
※エラーハンドリングの追加と、関数の分割をしています。

export async function getSortedPostsData() { const url = 'https://api.github.com/repos/satorun082/article/contents' let files // Error Handling try { files = await requestGithubApi(url) } catch (error) { return [errorObject(error)] } const fileNames = files.map((file) => file.name) // Get Posts Promises const allPostsPromise = fileNames.map((fileName) => getPostsData(fileName)) // Resolve Posts Promises const allPostsData = await Promise.all(allPostsPromise) // Sort posts by date return allPostsData.sort(({ date: a }, { date: b }) => { if (a < b) return 1 if (a > b) return -1 return 0 }) } async function requestGithubApi(url) { const response = await fetch(url) if (response.status != 200) throw new Error(response.statusText) return await response.json() } async function getPostsData(fileName) { // Remove ".md" from file name to get id const id = fileName.replace(/.md$/, '') const url = `https://api.github.com/repos/satorun082/article/contents/${id}.md` let content try { content = await requestGithubApi(url) } catch (error) { return errorObject(error) } // Use gray-matter to parse the post metadata section const matterResult = matter(base64.decode(content.content)) // Combine the data with the id return { id, ...matterResult.data, } } function errorObject(error) { return { id: 'api error', date: '', title: error.message } }

投稿2021/08/14 06:16

編集2021/08/14 08:42
k4a

総合スコア983

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

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

HelloQ

2021/08/14 06:43

回答の程、ありがとうございます. 仰る通りでawait/asyncをあまり理解していないです. また仰る通り、エラーが発生することにより外しておりました.(実はmap内に記述してもエラー内容が発生したので自暴自棄になっていたのは認めざる負えません...) await/asyncを記述してのエラー内容を新しく記述して置きましたので、お時間がございましたら回答の程宣しくお願いします.
HelloQ

2021/08/14 11:26

ありがとうございます. 非常に勉強になりました. まだよく分かっていないので、コードを参考にしながら意味を理解していきたいと思います.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問