オブジェクトから値だけを取り出す方法
apiの値を変数に代入する際に、以下のような方法だと可読性が上がります。
const obj = {name: "ko", age: 23, female: true} const {name, age, female} = obj; console.log(name); // "ko"
{ var } に代入すると、オブジェクトのキーがvarの値だけを取得できます。
const {name, age, female} = obj;
コンポーネントにpropsを渡すときに、
このモジュール内で使用するapiの値を1行目で確認する役割もあるので便利です。
export default function ArticleDetails({ article }) { // (ふーん。 サムネとタイトルと記事内容を扱うんだ...) const { thumbnail, Title, detail} = article.fields return ( <div> <div className="banner"> <Image src={"https:" + thumbnail.fields.file.url} width={thumbnail.fields.file.details.image.width} height={thumbnail.fields.file.details.image.height} /> <h2>{ Title }</h2> </div> <div className="detail"> <h3>detail</h3> <div>{ documentToReactComponents(detail) }</div> </div> </div> ); };
おしまい
【contentful】Rich Text を表示するために documentToReactComponents関数 を使う
記事の詳細を作成するときに
記事内容をRich Text で記述するようにしました。
他の項目のようにpropsを渡すだけではなかったので方法を記述します。
contentfulの取得方法はこちら↓ https://okinawanpizza.hatenablog.com/entry/2021/10/21/010930
documentToReactComponents()
contentful側の関数で、リッチテキストの中身を読んでくれる関数のようです。
- ライブラリをインストール
npm install --save contentful @contentful/rich-text-html-renderer
- documentToReactComponentsをインポート
import { documentToReactComponents } from '@contentful/rich-text-html-renderer';
- リッチテキストの項目を引数にして以下のように記述
export default function ArticleDetails({ article }) { const {Title, detail} = article.fields return ( <div> <div className="detail"> <h3>detail</h3> <div>{ documentToReactComponents(detail) }</div> </div> </div> ); };
これで記事詳細を出力できます。
おしまい
【Next.js】【contentful】動的なルーティングを利用した詳細ページの作成
こんにちは、本日はcontentfulのエントリーの内容を詳細ページに追加していこうと思います。
なお、エントリーは一記事単位の呼び方です。
(下記図参照)
結果
以下が全体図です。
//pages/posts/[slug].js import { createClient } from "contentful"; import Image from "next/image"; import { documentToReactComponents } from "@contentful/rich-text-react-renderer" const client = createClient({ space: process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID, accessToken: process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN, }); export const getStaticPaths = async () => { //article 全件取得 const res = await client.getEntries({ content_type: "article" }) //全件のパラメーターだけを配列形式で取得 //[ { params: { slug: 'test2' } }, { params: { slug: 'test1' } } ] const paths = res.items.map(item => { return { params: { slug: item.fields.slug } } }) return { paths, fallback: false } } export async function getStaticProps({ params }) { const { items } = await client.getEntries({ content_type: "article", "fields.slug": params.slug }) return{ props: { article: items[0] } } } export default function ArticleDetails({ article }) { const { thumbnail, Title, detail} = article.fields return ( <div> //省略 </div> ); };
Dynamic Routes(動的なルーティング)
Next.jsでは設定したファイル名が自動的にスラッグになります。
また[params].js
などのようにしてファイル名に角括弧(ブラケット)を使うことで
動的なルーティングを作成できます。
つまり
* pages/post/create.js
は /post/create
にマッチします。
* pages/post/[sulg].js
は /post/1
や /post/abc
にマッチします。
contentfulのインポート
contentfulをインポートします。
import { createClient } from "contentful";
spaceIDとaccessTokenを入力し
contentfulにアクセスするapiを取得します。
const client = createClient({ space: process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID, accessToken: process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN, });
それぞれのエントリーのslug名を全件取得
content_type
がarticle
のエントリー(記事)をjson形式で取得、
それぞれのslugと言う項目だけを返すようにします。
下記のような形が返却されます。
[ { params: { slug: 'test2' } }, { params: { slug: 'test1' } ,....} ]
//article 全件取得 const res = await client.getEntries({ content_type: "article" }) //全件のパラメーターだけを配列形式で取得 //[ { params: { slug: 'test2' } }, { params: { slug: 'test1' } } ] const paths = res.items.map(item => { return { params: { slug: item.fields.slug } } }) return { paths, fallback: false }
ちなみにslugのcontentful側での設定は
content model から手動で設定しているものになります。
urlに該当するエントリーを取得
現在のurlに該当するエントリーをgetEntries関数で取得し
コンポーネント側にpropsを渡します。
export async function getStaticProps({ params }) { const { items } = await client.getEntries({ content_type: "article", "fields.slug": params.slug }) return{ props: { article: items[0] } } } export default function ArticleDetails({ article }) { console.log(article) return ( <div> //省略 </div> ); };
以上です!、、思ったより手こずりました。
ただ、youtubeで英語でガッツリ解説してくれている動画を見つけて
そこから意外とスムーズにいきました。
おしまい
【Next.js】getStaticPropsでurlを取得することが可能
//http://localhost:3000/posts/test2 export async function getStaticProps({ params }) { console.log(params) // {slug: "test2"} const { items } = await client.getEntries({ content_type: "article", "fields.slug": params.slug }) return{ props: { article: items[0] } } }
自分が書いているcontentfulを使ったブログの一部分。
getStaticProps({ params }) を用いるとparamsに{ slug: 'test2' }
が格納される。
useRouterを使わないと取得できないのかと思っていてびっくり。
【Next.js】contentfulのコンテンツをNext.js 側で取得する
contentfulと言うHeadlessCMSで作成した記事内容をNext.js側に出力する方法について。
手順
- contentfulをインストール
- データの取得
- コンポーネントに渡す
contentfulをインストール
- npmでインストール
npm install contentful
- index.jsxインポート
import { createClient } from "contentful";
データの取得
以下を記述
// index.jsx export async function getStaticProps() { const client = createClient({ space: process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID, accessToken: process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN, }); const res = await client.getEntries({content_type: "blog"}); return { props: { articles: res.items } } }
.env.localを作成し以下を記述
NEXT_PUBLIC_CONTENTFUL_SPACE_ID=(①) NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN=(②)
settings→APIkeys→Add API key を押すと下の画像のような画面になるので
space ID と access Token をそれぞれに渡します。
コンポーネントに渡す
articles: res.items
と設定しているので、articlesをプロップスとして渡します。
export default function Home({ articles }) { console.log(articles); }
以上!
【JavaScript】default export と default import について
モジュールの読み込み時によく見かける {}
と
そうでないものの違いがわからなかったのでまとめてみました。
今回は default export と default import について。
import React from "react"; import { BookDescription } from "./BookDescription";
default export (名前なしexport)
- 他のファイルで利用するために export を宣言する
- アロー関数だとファイルの最後に
export default (関数名)
を追記 - 名前付き関数だと関数宣言時に
export default
を追記
//アロー関数 const Title = (props) => { return <h2>{props.title}</h2> } export default Title;
//名前付き関数 export default function Title(props) { return <h2>{props.title}</h2> }
default import (名前なしimport)
- default export で指定した名前を import 時につける
- default export でファイルごと読み込む時は ファイル名も同じ名前であることが多い
// Title.jsx ~~~ export default Title;
// App.jsx import Title from ".Title";
おわり
この辺り意外とこんがらがっているので改めて整理できてよかったです。
明日は名前付きのexport import についての記事を書こうとおもいます。
おしまい
【typescript】interfaceは拡張ができる、typeは拡張ができない
今回は type と interface の違いについて。
# オブジェクトに型を定義する
アノテーションの部分をオブジェクト{}
にすることで可能。
※型アノテーション = stringやbooleanのような注釈をつけて型を定義すること
//通常の型アノテーション let name: string = "tamakipedia"; //オブジェクトの場合 let obj: {name: string, age: number, isHandsome: boolean} = { name: "tamakipedia", age: 20, isHandsome: true }
interface
オブジェクトの型アノテーションは長すぎると読みづらいので
名前をつけることが可能。
// オブジェクトの型を定義 interface Human { name: string, age: number, isHandsome: boolean } //型をHumanにする let obj: Human = { name: "tamakipedia", age: 20, isHandsome: true } let obj.name = 20 //Type 'number' is not assignable to type 'string'
type
interfaceもtype同様、型に名前をつけて参照できるようにします。
こちらはタイプエイリアスと呼ばれるそうです。
// 代入してる type Human = { name: string, age: number, isHandsome: boolean }
type と interface の違い
interfaceは拡張ができる
interface Human { name: string, age: number, isHandsome: boolean } //新しいプロパティを追加 interface Human { isAdorable: boolean } //型をHumanにする let obj: Human = { name: "tamakipedia", age: 20, isHandsome: true, isAdorable: true }
おしまい
今読んでいる参考書にはinterfaceを使っていることが多く、
別の記事にtypeを使ったチュートリアルがあったので調べてみました。
拡張できると可読性が低くなるので使用注意ですね!!