Column
Mar 9, 2022 09:39 PM
Date
Mar 8, 2022 23:49
Hashtags
English
Tech
Slug
How_I_developed_this_blog_Next_js_and_notion_a115cba1b20c4f6ca9d0001719f793f7
Published
Published
The structure is really simple. Next.js server calls notion API to get posts information from the notion table. The below image is my memo before coding.
This is the code of this blog.
This is my first time writing a tech post in English, so if you have any pointers, whether about programming or English, please send a comment on the notion page below.
Contents
- Why Next.js
- Why Notion
- React Notion X
- Code
- Reflections
1. Why Next.js
Next.js is React framework that can be used for developing web applications functionalities such as server-side rendering(SSR) and Static-Site Generating(SSG).
The reason why I used it in this blog system is that it’s really easy to develop web applications including using Vercel. Also, SSG is a good structure to make a light and fast website.
We have the option of using SSR, SSG and using both of them by Next.js. SSR renders pages by each request. In contrast, SSG generates pages when updated.
SSR is Subway; you start cooking after ordering, so it is easy to handle even if each person's order is different. It means it’s a better method for sites like Twitter, where everyone posts a lot.
SSG is KFC; you can put the fried chicken up beforehand and serve it when ordered because normally most customers orders basic fried chicken. It means it’s a better method for sites like blogs that don’t update content frequently.
Thus, I used SSG in this blog system, and the blog is now light and fast.
2. Why Notion
I used notion as editor of this blog.
I like the notion: good design and markdowns. However, the biggest reason why I want to use notion as editor of the blog is high-performance database table functions.
I can date information and tag information as hashtags with coloring that makes high visibility. Also, I can filter, sort, and search by using this information on the notion page.
With notion, I no longer need to create a sophisticated editor that is difficult to create and an administration page to manage the articles I have written.
3. React Notion X
React Notion X is a wonderful library. For the reason stated in the previous chapter, I decided to use the notion and have come to the conclusion that I would like to display the post on my blog without changing the notion design.
Then, I found the perfect library which fulfilled my request.
This library provides some functions. One of them is getting notion page data, and just passing that data to NotionRender, it renders that notion page by the same design.
Thanks to the notion and this library, I don't even have to write the design in CSS anymore.
4. Code
This blog is really simple. Using compornents/notion/index.tsx for get data from notion, then reander at pages/index.tsx and pages/posts/[slug].tsx.
compornents/notion/index.tsx
This code has some functions which get data from notion by using Notion API and notion-client which is provided to get page content for React Notion X render.
Some parts are omitted by using “~~~~”.
export const getPosts = async ( databaseId: string) => { const response = await notion.databases.query({ database_id: databaseId, }) const { results } = response let posts = results.map((result:any) => { const d = result.properties // ~~Add slug if it is empty~~ const item:any = { id: result.id, url: result.url, slug: '', title: '', date: '', edited: result.last_edited_time, published: false, hashtags: [], recordMap: {}, } Object.keys(d).forEach((key) => { // https://github.com/masaishi/notion-blog/blob/main/compornents/notion/index.tsx~~Converting data into a form that fits the form~~ }) // ~~Add date if it is empty~~ posts = posts.filter((post): post is Post => typeof post !== 'undefined'); // Sort database by date. posts.sort((a, b) => b!.date - a!.date); return posts } // Get page detail export const getPage = async (pageId: string) => { const page = await notionApi.getPage(pageId); return page } export const updateProperties = async (pageId: string, properties: any) => { const response = await notion.pages.update({ page_id: pageId, properties, }); } export const getHashtags = async () => { const response = await notion.databases.query({ database_id: process.env.NOTION_DATABASE_ID ?? '', }) const { results } = response as any let hashtags:Hashtag[] = [] for(const result of results){ const d = result.properties! as any for(const select of d.Hashtags.multi_select) { if(!hashtags.filter(hashtag => hashtag.name == select.name).length){ hashtags.push({'name':select.name, 'color':select.color, 'count':1}) }else{ hashtags.filter(hashtag => hashtag.name == select.name)[0].count += 1 } } } hashtags = hashtags.sort((a, b) => b.count - a.count); return hashtags }
getPosts is a function to get data from the notion database table.
This page tells me how to use Notion API for Next.js.
This code is described by the upper article. This code which makes a portfolio with next.js and the notion is really helpful.
This code doesn’t use React Notion X, but this code tells me how to get data from the notion database table.
pages/index.tsx
After using getPosts to get posts data, it filter posts depends on hashtags and put in show_posts. The below code is one part in pages/index.tsx.
{show_posts.map((post:Post) => ( <div className="card mt-5" key={post.id}> <PostContent post={post} /> </div> ))}
PostContent is one compornent in layout.
import React from 'react' import Head from 'next/head' import Image from 'next/image' import Link from 'next/link' import styles from '../styles/Home.module.css' import { NotionRenderer } from 'react-notion-x' import { Post } from '../notion/postType' export const PostContent = ({post}:{post:Post}) => { return ( <div className="card-body" key={`${post.id}_content`}> <div className='notion light-mode notion-page notion-block'> <div className="card-title d-flex align-items-center"> <div className="profile align-items-center"> <Link href={`/posts/${post.slug}`}> <a className="h2 mb-0 notion-link" id={`${post.id}_title`}>{post.title}</a> </Link> </div> </div> <h6 className="card-subtitle mb-2 text-muted" id={`${post.id}_published_at`}>posted_at:&ensp;{new Date(post.date ?? '').toLocaleString()}</h6> <h6 className="card-subtitle mb-2 text-muted" id={`${post.id}_edited_at`}>edited_at: &ensp;{new Date(post.edited).toLocaleString()}</h6> <div className="d-flex"> {post.hashtags?.map((hashtag) => { return ( <div key={`${post.id}_${hashtag}`} className="me-3"> <Link href={`/?hashtags=${hashtag}`}> <p className="h6 mb-0 notion-link">#{hashtag}</p> </Link> </div> ) })} </div> </div> <div className="card-text mt-4 post-content contents-texts"> {/* <div className="card-text post-content contents-texts" id={`${post.id}_contents`}> */} <NotionRenderer recordMap={post.recordMap} fullPage={false} darkMode={false} /> </div> </div> ) }
As you can read, it just passes the post received as an argument to the render of React Notion X
Only these two codes are big parts of this blog. I think the reason I was able to develop this blog in such a short time was that I was able to find , a code that did almost exactly what I wanted to do.
5. Reflections
Since I had already created a site with next.js and react-notion-x, I was able to create the blog itself almost in one day, and the below table is how much time I spend to develop
Contents | Time |
Render posts at the index page | 2h 30m |
Detail pages | 2h 5m |
Hashtag | 2h 55m |
Others | 1h 40m |
The goal I have established in developing this blog was to finish that within a weekend, and I think using notion and React Notion X was the reason I achieved it.
When developing something, a thinking structure that is easy to develop is just as important as how to code, and I think I came up with a very good way this time, so that was good.
However, I have a reflection point on the coding part. I used “any” and “!” many times for passing compile.
I have only worked with dynamically typed languages so far, so I want to learn not only how to write typescript, but also its philosophy and design patterns of statically typed language.
To sum up, I need to study typescript and statically typed language more, but I think the blog itself was created just fine. I developed a hashtag filter function, so I can make links to show only English pages or Japanese pages.
In conclusion, both Next.js and notion are great, and I will continue to use them!