tamakipedia

フロントエンドエンジニア。Typescriptもう特訓中です。一日の振り返りや学んだことをちょっとずつ吐いています。

オブジェクトから値だけを取り出す方法

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>
  );
};

これで記事詳細を出力できます。

参考
https://www.contentful.com/developers/docs/javascript/tutorials/rendering-contentful-rich-text-with-javascript/

おしまい

【Next.js】【contentful】動的なルーティングを利用した詳細ページの作成

こんにちは、本日はcontentfulのエントリーの内容を詳細ページに追加していこうと思います。
なお、エントリーは一記事単位の呼び方です。
(下記図参照)

f:id:okinawanpizza:20211024201207p:plain

結果

以下が全体図です。

//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_typearticleのエントリー(記事)を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 から手動で設定しているものになります。
f:id:okinawanpizza:20211024214937p:plain

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' }が格納される。

nextjs.org

useRouterを使わないと取得できないのかと思っていてびっくり。

【Next.js】contentfulのコンテンツをNext.js 側で取得する

contentfulと言うHeadlessCMSで作成した記事内容をNext.js側に出力する方法について。

手順

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 をそれぞれに渡します。
f:id:okinawanpizza:20211024073709p:plain

コンポーネントに渡す

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を使ったチュートリアルがあったので調べてみました。
拡張できると可読性が低くなるので使用注意ですね!!

参考 https://zenn.dev/luvmini511/articles/6c6f69481c2d17