Next.js入門
Data Fetching (Pre-rendering)
ページがレンダリングされる前にデータをパッチする必要があります.
既存のリアクターでは、ページが最初にロードされ(このときデータは通常[]が空)、useEffectの実行に伴い、中のデータキャプチャロジックが実行され、受信したデータがstateにロードされ、stateが変化するため、2回目のロードが行われる.
でもnextjsでレンダリングされたHTMLページは、2回目のレンダリングを待つことはありません.つまり、データの修正を待たない.この問題を解決するためにnext.jsのデータパッチ(getInitialiProps、getStaticProps、getStaticPath、getServerSideProps)を使用して、最初のレンダリングでデータがパッチされるようにデータを処理する必要があります.
すべてのページに共通のデータパッチが必要な場合、app.jsでデータを事前にパッチすればよい. ページごとに異なるデータが必要な場合は、ページごとにデータをパッチできます.
グローバルデータパッチ
すべてのページに共通のデータパッチが必要な場合、つまりグローバルパッチが必要な場合はgetInitialPropsを使用する必要があります.
// pages/_app.js
import { NextPageContext } from 'next'
function MyApp({ Component, pageProps }) {
return (
<>
<AppLayout>
<Component {...pageProps} />
</AppLayout>
</>
);
}
MyApp.getInitialProps = async (context:NextPageContext) => {
const { ctx, Component } = context;
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
return { pageProps };
};
ページ単位のパッチデータ
実際、getInitialPropsでデータをページ単位でパッチできます.ただし、静的データであるかページリクエストによるデータであるかによって、getStaticProps/getStaticPath/getServerSidePropsに分離します.
Next.jsのプリレンダリングには2つの形式があります.
// pages/blog.js
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}
export async function getStaticProps() {
const res = await fetch('https://.../posts')
const posts = await res.json()
return {
props: {
posts,
},
revalidate: 3600 //3600초마다 다시 빌드(데이터가 가끔 바뀔때 유용함)
}
}
export default Blog
getStaticPaths:動的ルーティング+getStaticProps-ページが動的ルーティングに書き込まれ、getStaticPropsに書き込まれている場合は、getStaticPathsを使用して構築時に静的にレンダリングするパスを設定する必要があります.
// pages/posts/[id].js
function Post({ post }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}
export const getStaticPaths = async () => {
const res = await fetch('https://.../posts')
const posts = await res.json()
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// { fallback: false } 는 다른 routes들은 404임을 의미
// true이면 만들어지지 않은 것도 추후 요청이 들어오면 만들어 줄 거라는 뜻
return { paths, fallback: false }
}
export const getStaticProps = async ({ params }) => {
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
return { props: { post } }
}
export default Post
getServerSideProps:構築中は実行されず、各ページリクエストはサーバからデータを取得します.// pages/page.js
function Page({ data }) {
console.log(data)
}
export const getServerSideProps = async (context) => {
const res = await fetch(`https://.../data`)
const data = await res.json()
return { props: { data: data } }
}
export default Page
公式サイトでは、必要に応じてgetServer SidePropsのみを使用することを推奨しています.File-based Routing
Fullstack Framework
Next.jsにより、開発者はreactプロジェクトにバックエンドapiを簡単に追加できます.Reactプロジェクトには、データのロード、ストレージ、認証、認証プロセスを追加できます.(Node.js構文を使用)
pagesフォルダの下にapiフォルダを追加し、apiパスに対応する名前のファイルを生成するだけです.
// api/new-meetup.js
import { MongoClient } from 'mongodb';
async function handler(req, res) {
if (req.method === 'POST') {
const data = req.body;
const client = await MongoClient.connect();
const db = client.db();
const meetupsCollection = db.collection('meetups');
const result = await meetupsCollection.insertOne(data);
console.log(result);
client.close();
res.status(201).json({ message: 'Meetup inserted!' });
}
}
export default handler;
以上のように、モンゴルdbストレージデータにアクセスするロジックを記述することができる.// new-meetup/index.js
import { useRouter } from 'next/router';
import NewMeetupForm from '../../components/meetups/NewMeetupForm';
function NewMeetupPage() {
const router = useRouter();
const addMeetupHandler = async (enteredMeetupData) => {
const response = await fetch('/api/new-meetup', {
method: 'POST',
body: JSON.stringify(enteredMeetupData),
headers: {
'Content-Type': 'application/json'
}
});
const data = await response.json();
console.log(data);
router.push('/');
}
return (
<NewMeetupForm onAddMeetup={addMeetupHandler} />
)
}
export default NewMeetupPage;
上記のように、fetch関数でapiフォルダの下のファイルパスを指定できます.その他
Nexst.jsはImageラベルを提供します.次に、使用する画像ファイルのurlドメインです.config.jsに登録してから画像アドレスを使用できます.
// next.config.js
const nextConfig = {
reactStrictMode: true,
images: {
domains: ['yt3.ggpht.com', 'i.ytimg.com']
}
}
module.exports = nextConfig
userouterを使用できます.// [newsId].js
// our-domain.com/news/[newsId]
import { useRouter } from 'next/router';
function DetailPage() {
const router = useRouter();
console.log('router: ', router);
const newsId = router.query.newsId;
console.log('newsId: ', newsId);
const onClinckHandler = () => {
router.push('/')
}
return <button onClick={onClickHandler}>The Detail Page</button>
}
export default DetailPage;
our-domain.com/news/123に入り、コンソールウィンドウは以下のようになります.context.params
import MeetupDetail from '../../components/meetups/MeetupDetail';
function MeetupDetails() {
return (
<MeetupDetail />
)
}
export async function getStaticPaths() {
return {
fallback: false,
paths: [
{
params: {
meetupId: "m1",
}
},
{
params: {
meetupId: "m2",
}
}
]
}
}
export async function getStaticProps(context) {
console.log('PARAMS: ', context.params);
const meetupId = context.params.meetupId;
return {
props: {
meetupData
}
}
}
export default MeetupDetails;
Headタグを使用したメタデータの追加// pages/index.js
import Head from 'next/head';
import MeetupList from '../components/meetups/MeetupList';
import { Fragment } from 'react';
function HomePage(props) {
return (
<Fragment>
<Head>
<title>React Meetups</title>
<meta
name='description'
content='Browse a huge list of highly active React meetups!'
/>
</Head>
<MeetupList meetups={props.meetups} />
</Fragment>
)
}
各ページのインデックス.jsでは、タグに必要なコンテンツを追加できます.(SEOに良い)Next.jsでのApollo Graphqlの使用
従来の方法:useQueryの使用
import React from 'react'
import Image from 'next/image';
import VideoCard from './components/videoCard';
import { useQuery, gql } from '@apollo/client';
import styles from './channel.module.css';
const GET_DATA = gql`
query channel_channelInfo(
$id: String
$userId: String
) {
channel_channelInfo(
id: $id
userId: $userId
) {
title
description
banner
}
}
`;
export default function Channel() {
const { error, loading, data} = useQuery(GET_DATA, {
variables: {
id: 'abcdefg',
userId: 'Chaster'
}
})
if(loading) return <p>Loading...</p>
if(error) return <p>Error...</p>
const channelData = data.channel_channelInfo;
return (
<div>
<Image
src={channelData.banner}
alt='alt'
height={270}
width={1500}
/>
<h2 className={styles.title}>{channelData.title}</h2>
<p className={styles.desc}>{channelData.description}</p>
<VideoCard videos={channelData.video}/>
</div>
)
}
Next.jsからApolloにデータを受信// graphqlClient.js
import { ApolloClient, InMemoryCache } from '@apollo/client';
export const graphqlClient = new ApolloClient({
uri: 'https://api.dev.vling.net/graphql',
cache: new InMemoryCache()
});
import React from 'react'
import Image from 'next/image';
import VideoCard from './components/videoCard';
import { gql } from '@apollo/client';
import { graphqlClient } from './graphqlClient';
import styles from './channel.module.css';
const GET_DATA = gql`
query channel_channelInfo(
$id: String
$userId: String
) {
channel_channelInfo(
id: $id
userId: $userId
) {
title
description
banner
}
}
`;
export default function Channel({ data }) {
const channelData = data.channel_channelInfo;
return (
<div>
<Image
src={channelData.banner}
alt='alt'
height={270}
width={1500}
/>
<h2 className={styles.title}>{channelData.title}</h2>
<p className={styles.desc}>{channelData.description}</p>
<VideoCard videos={channelData.video} />
</div>
)
}
export const getStaticProps = async () => {
const { data } = await graphqlClient.query({
query: GET_DATA,
variables: {
id: 'abcdefg',
userId: 'Chaster'
}
});
return {
props: {
data
}
};
}
references
https://nextjs.org/docs
https://velog.io/@devstone/Next.js-100-活用-feat-initialProps-webpack-storybook
Reference
この問題について(Next.js入門), 我々は、より多くの情報をここで見つけました https://velog.io/@ktg6360/Next.js-시작해보기テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol