Error getstaticpaths is required for dynamic ssg pages and is missing for

You will learn how to make use of Next.js getStaticPaths & getStaticProps on a dynamic route to create a Master-Detail UI commonly used in modern web apps.

Table of contents

  • 1 What is getStaticPaths?
  • 2 What is a Master-Detail UI pattern ?
  • 3 Implementing a Master-Detail UI in Next.js
  • 4 getStaticProps with a context parameter
  • 5 getStaticPaths for pages on dynamic routes
    • 5.1 paths property
    • 5.2 fallback property 
  • 6 President function:  the React component
    • 6.1 Handling Error When fallback: true
  • 7 Summary

What is getStaticPaths?

getStaticPaths is another special function in Next.js used in conjunction with getStaticProps for dynamic routes. In other words, you can use getStaticPaths on a page that uses a dynamic route, and whenever you use this function on that page, there must be a getStaticProps function as well.

[sample].js

The blocks diagram of a page on dynamic route

What is a Master-Detail UI pattern ?

Imagine you are developing a website with the following user interfaces. You may have seen this pattern many times when you browse the web. This UI pattern is called the Master-Detail pattern.

Master-Detail UI

in this post, I am going to display a list of US presidents on the master page, and on the details page, I will show some facts about each president.

Implementing a Master-Detail UI in Next.js

Note: If you are new to Next.js, please learn how to set up a Next.js project and Next.js routing. 

  1. Open the terminal and run npx create-next-app demo-next-app
  2. Open the project folder in your favorite editor 
  3. We are going to create the main page ( master UI ) on the localhost:3000/presidents. Therefore, in the pages folder, create another folder named “presidents
  4. Inside the “presidents” folder, create a file: index.js, and add the code below to it. 
import Link from 'next/link';

function PresidentList( { presidents }){
    return( 
        <>
            <p>List of US presidents</p>
            {
                presidents.map( 
                    president =><div key={ president.id }>
                        
                        <Link href= { `presidents/${president.id}`}>
                            <li><a>{ president.name }</a></li>
                        </Link></div>
                 
                 )
            }
        </>
    )
}

export default PresidentList
 
 
export async function getStaticProps(context){

        const response = await fetch('https://api.sampleapis.com/presidents/presidents',{
            method:'GET',
            headers:{
                'Content-Type':'application/json'
            }
        });
        const data = await response.json();
        
        return {
            props:{
                presidents: data.slice(0,3),//take only 3 names from the list
            },
        }
}
  1. This code uses getStaticProps. I have a post on getStaticProps that explain getStaticProps and the code below.
  2. When a user clicks on a name of a president, we need to display the details about that president on the details page. For this reason, we need to have a dynamic route. The route will be localhost:3000/president/presidentId.
  3. presidentId is a dynamic parameter. Its value is determined when the user clicks on the name of the president. 
  4. Now, create another file in the president’s folder. This time name it as [presidentId].js,and add the following code to it.
  5. There are three functions in this file:
    1. getStaticProps(context)
    2. getStaticPaths()
    3. President({ president })
function President( { president }){  

    return( 
        <>
            <h1>President : { president.name }</h1>
            {
                 
             <div>
                <label>Years in office: </label>{ president.yearsInOffice }<br />
                <label>Vice president: </label>{ president.vicePresidents }<br />
                <img src={ president.photo } />
             </div>
                 
            }
        </>
    )
}

export default President

export async function getStaticPaths(){
    return {
        paths:[
            { params:{ presidentId: '1' }  },
            { params:{ presidentId: '2' }  },
            { params:{ presidentId: '3' }  }
        ],
        fallback:false
    }
}

 
export async function getStaticProps(context){
    const { params } = context;
    console.log( context)
    const response = await fetch(`https://api.sampleapis.com/presidents/presidents/${ params.presidentId }`,{
        method:'GET',
        headers:{
            'Content-Type':'application/json'
        }
    });
    const data = await response.json();
   
    return {
        props:{
            president: data,
        },
    }
}

getStaticProps with a context parameter

getStaticProps function that so far we have seen had no parameter. But, it can take a parameter. The term “context” is used in convention, but you can use any appropriate name.

export async function getStaticProps(context) {
  return {
    props: {}, 
  }
}

A context is an object with key-value pairs. It has the params, preview, previewData, locale, locales, and defautLocale as the keys. For our example, we are going to utilize the params key. 

Params key contains the route parameters of the dynamic route. For example, [presidentId].js is in the form of params: { presidentId: … }. The value of presidentId depends on the user’s choice from the list of names.

As mentioned before, we need getStaticPaths on a page that uses a dynamic route. If you do not this function, a run-time error will generate.

Error: getStaticPaths is required for dynamic SSG pages and is missing for ‘/presidents/[presidentId]’.
Read more: https://nextjs.org/docs/messages/invalid-getstaticpaths-value

Unlike getStaticProps, getStaticPaths runs only at the build time. It returns an object with the two required properties: paths and fallback.

paths property

This property determines which path should be pre-rendered. Its value is an array of objects. Each object has a params property, which itself is another object. This object has the key ‘presidentId’ which is the parameter used in the dynamic route. Notice that the value of presidentId is a string.

In the above code, I have only three elements in the array. Therefore, I can hard-code the parameters to match the presidentId. But, what if you have a large number of items. It is not practical to hard-code all the values. 

Depending on the logic of your application, the method you would get the ids can be different. In this example, I am going to make an API call and iterate through the array of objects to get the ids. 

export async function getStaticPaths(){
    const response = await fetch('https://api.sampleapis.com/presidents/presidents',{
            method:'GET',
            headers:{
                'Content-Type':'application/json'
            }
        });
   
    const data = await response.json();
   
    //creating an array of objects
    const paths = data.map( president => {
            return {
                params :{ presidentId: `${president.id }`}
           
            }
        }
           
    )

 
    return {
        paths,
        fallback:true
    }
}

Note: You need to make another change in president/index.js so that you will see all the names of the presidents on the master page. 

Modify the code in getStaticProps in this file in the return statement as below. 

return {
            props:{
                presidents: data,//slice method has been removed
            },
        }

fallback property 

This property can take 3 values: false, true, and blocking. How getStaticProps runs changes based on this property.

fallback: false fallback: true fallback:’blocking’
For the paths specified in the Paths property The paths returned from getStaticPaths will be rendered to HTML at build time by getStaticProps. The paths returned from getStaticPaths will be rendered to HTML at build time by getStaticProps The paths returned from getStaticPaths will be rendered to HTML at build time by getStaticProps
For the paths not specified in the Paths property Generate a 404 page Serve a “fallback” version of the page on the first request. In the background, HTML and JSON files are statistically generated relevant to the newly requested path, which means getStaticProps runs during this period. Server-side rendering(SSR) on the first request & send the response as HTML. The getStaticProps runs before the initial rendering.
As a response from the server, the browser receives the JSON for the generated path. Next.js utilize this file to render the page with the required props. 

A user will notice an automatic transition from a “fallback”  page to the full page(the page with props) on the browser.

When complete, the browser receives the HTML for the generated path. The user might experience a small delay in rendering the full page requested, but, there is no loading/fallback state during this period. 
A subsequent request to the path will handle just like other pre-rendered pages at the build time. A subsequent request to the path will handle just like other pre-rendered pages at the build time.
When to use Simple applications with a limited number of paths to pre-render.

When you do not need to add new pages to your site.

For apps with a large number of static pages. This will save time in creating pages in the build time. For apps with a large number of static pages.

If the customer does not a loading indicator message until the actual page they need is rendered.

President function:  the React component

This is a regular React function responsible for displaying the output. It will use the president prop returned by the getStaticProps. You need to do some modification to the code in this function when the fallback property in getStaticPaths is true.

Handling Error When fallback: true

When you run the next build when the fallback is true, you will get a Build error if you do not handle the condition when the page props are not yet available. You can modify the code in function President in [presidentId].js to handle this condition.

import { useRouter } from "next/router"; //add this line

function President( { president }){
    const router = useRouter(); //add this line

    if( router.isFallback ){			 //add this line 
        return <h2>The Page is loading...</h2>	 //you can add any styles or have a custom page
    }
   
    return(
        <>
            <h1>President : { president.name }</h1>
            {
                 
             <div>
                <label>Years in office: </label>{ president.yearsInOffice }<br />
                <label>Vice president: </label>{ president.vicePresidents }<br />
                <img src={ president.photo } />
             </div>
                 
            }
        </>
    )
}

Summary

  • Use getStaticPaths on pages on dynamic routes
  • getStaticPaths run only at build time
  • It must be used with getStaticProps
  • getStaticPaths returned an object with two properties: paths & fallback
  • Paths property determines the path to be pre-rendered
  • The behavior of the getStaticProps changes based on the fallback property

Ashutosh

Ashutosh

Posted on Apr 25, 2021

• Updated on Apr 26, 2021

This article is originally posted at Link

In the last article, we learn how to use getStaticProps() in the Next.js application. In Next.js, we can pre-render a page during build time. We generate all the HTML code and data in advance. And the data is later cached by the server.

This approach works well for the static paths but, it fails when we have to pre-render pages for dynamic paths. And it makes sense. Let’s say there is a blog and, there are multiple articles under it. And it next.js we defined dynamic paths like [blogId].js. As we already know, this path is valid for blog id 1, 2, 3, 4, and so on. There is no way Next.js knows how many pages it has to render.

To accomplish this, getStaticPath() is another function we use in this article.

To create the Next.js app, please follow this article.

Let’s add a directory named blog under the pages folder. And add another route [blogId].js under the blog directory.

Just to start with, please add the following code:

function getBlogIdDetails(props){
    return (
        <div>
            Blog ID details pages
        </div>
    )
}

export  default getBlogIdDetails

Enter fullscreen mode

Exit fullscreen mode

Visit the URL, http://localhost:3000/blog/1 and, you will see «Blog ID details pages» on the browser.

Now create another file next.config.js and add the following:

module.exports = {
    webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
        config.node = {
            fs: 'empty', // This is required
        }
        return config
    }
}

Enter fullscreen mode

Exit fullscreen mode

Save the previous and create another file blogs_details.json and add the following content:

{

  "blogs": [

    { "id": "1", "title": "My First Blog", "description": "This is the content of first blog" },

    { "id": "2", "title": "My Second Blog", "description": "This is the content of second blog" },

    { "id": "3", "title": "My Third Blog", "description": "This is the content of third blog" },

    { "id": "4", "title": "My Fourth Blog", "description": "This is the content of fourth blog" },

    { "id": "5", "title": "My Fifth Blog", "description": "This is the content of fifth blog" },

    { "id": "6", "title": "My Sixth Blog", "description": "This is the content of sixth blog"}

  ]

}

Enter fullscreen mode

Exit fullscreen mode

The above file is our backend file, which we read using Next.js (Remember getStaticProps) and then dynamically load into our app.

Update the contents of the file [blogid].js

function getBlogIdDetails(props){
    return (
        <div>
            <h1><strong>{props.blogDetails.title} </strong> </h1>
            <br/>
            <p>{props.blogDetails.description}</p>
        </div>
    )
}

export async function getStaticProps() {
    return {
        props: {
            blogs: [{id: '1', title: 'title1'}, {id: '2', title: 'title2'}, {id: '3', title: 'title3'}]
        },
    };
}

export  default getBlogIdDetails

Enter fullscreen mode

Exit fullscreen mode

And now refresh the page «http://localhost:3100/blog/1».

At this point, you will see ‘Error: getStaticPaths is required for dynamic SSG pages’

Remember we discussed how getStaticProps() fails in dynamic paths.

Let’s get started with getStaticPaths().

Open the file [blogid.js] and import the following:

import fs from 'fs'
import path from 'path'

Enter fullscreen mode

Exit fullscreen mode

We need to import fs (to read the file) and path (To get the current working directory function) from node.js.
and then update the getStaticProps() function with:

export async function getStaticProps(context) {
    const { params } = context
    const blogId = params.blogid
    const fileToRead = path.join(process.cwd(), 'blogs_details.json')
    const data = JSON.parse(await fs.readFileSync(fileToRead))
    const blog = data.blogs.find(blog => blog.id === blogId)
    return {
        props: {
            blogDetails: blog
        },
    };
}

Enter fullscreen mode

Exit fullscreen mode

And add the function getStaticPaths() afterwards

export async function getStaticPaths() {
    return {
        paths: [
            {  params: { blogid: '1' } },
            {  params: { blogid: '2' } },
            {  params: { blogid: '3' } },
        ],
        fallback: false
    }
}

Enter fullscreen mode

Exit fullscreen mode

The getStaticPaths() function tells the Next.js to render the pages defined in paths. This function always returns the object.

Also, don’t forget to add the fallback keyword to the getStaticPaths() function.

The complete file will look like

import fs from 'fs'
import path from 'path'
function getBlogIdDetails(props){
    return (
        <div>
            <h1><strong>{props.blogDetails.title} </strong> </h1>
            <br/>
            <p>{props.blogDetails.description}</p>
        </div>
    )
}
export async function getStaticProps(context) {
    const { params } = context
    const blogId = params.blogid
    const fileToRead = path.join(process.cwd(), 'blogs_details.json')
    const data = JSON.parse(await fs.readFileSync(fileToRead))
    const blog = data.blogs.find(blog => blog.id === blogId)
    return {
        props: {
            blogDetails: blog
        },
    };
}
export async function getStaticPaths() {
    return {
        paths: [
            {  params: { blogid: '1' } },
            {  params: { blogid: '2' } },
            {  params: { blogid: '3' } },
        ],
        fallback: false
    }
}
export  default getBlogIdDetails

Enter fullscreen mode

Exit fullscreen mode

The fallback can help us if we have too many blogs in our app, which is quite normal. A blog has 100s or 1000s of articles and it is not a good idea to pre-generate all those pages in advance. We don’t want to pre-generate pages for the year-old blogs or the blogs which are not read enough by the users.

In that case, we set the fallback to true and delete all the other pages from the returned object. In our case let say, we don’t want to pre-generate blog 2 and blog 3 pages.

export async function getStaticPaths() {
    return {
        paths: [
            {  params: { blogid: '1' } }
        ],
        fallback: true
    }
}

Enter fullscreen mode

Exit fullscreen mode

And also update the function getBlogIdDetails

function getBlogIdDetails(props){
    const { blogDetails } = props;
    // This will return Loading and prevents the page from being crashed    
    if (!blogDetails ) {
        return <p>Loading....</p>
    }

    return (
        <div>
            <h1><strong>{props.blogDetails.title} </strong> </h1>
            <br/>
            <p>{props.blogDetails.description}</p>
        </div>
    )
}

Enter fullscreen mode

Exit fullscreen mode

The above code will only pre-generate the pages for blog 1. Though all the paths to the blogs are still valid.

Thanks for reading up to here. Will see you in the next article.

От автора: Next.js — это фреймворк React, который обязательно упростит вашу жизнь как разработчика. С его помощью можно абстрагировать общие и избыточные задачи (например, маршрутизацию) в относительно более простые и мощные API. Таким образом, вы можете сосредоточиться на написании приложений вместо того, чтобы изобретать колесо.

В последнее время Next.js позиционируется, как React Framework for Production, и с таким смелым заявлением он предлагает множество функций, которые помогут вам вывести ваши веб-сайты на React с нуля до готового состояния. Эти возможности имели бы меньшее значение, если бы Next.js был относительно сложен в освоении благодаря многочисленным функциям, которые подразумевают больше вещей и нюансов для изучения. Но его преимущество в простоте, мощности и большом инструментарии, это определенно является тем, что вам нужно иметь в своем арсенале.

По мере того, как вы начинаете изучать Next.js, есть некоторые вещи, с которыми вы, возможно, уже знакомы, и вы можете даже быть удивлены тем, насколько много вы можете сделать с его помощью, что может показаться потрясающим на первый взгляд. Next.js предназначен для статических сайтов, и он был хорошо спроектирован для этой цели. Но он также идет дальше с помощью постепенной статической регенерации, которая хорошо сочетается с существующими функциями, чтобы сделать разработку комфортнее. Но подождите, спросите вы, почему именно Next.js?

Это руководство будет полезно разработчикам, которые хотят начать работу с Next.js или уже начали, но которым необходимо заполнить некоторые пробелы в знаниях. Вам не нужно быть профессионалом в React, однако опыт работы с React пригодится.

Почему именно Next.js?

1. Относительно прост в изучении.

JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Узнать подробнее

Вот и все. Если вы хоть раз писали React, вы бы почувствовали себя как дома с Next.js. Он предлагает вам расширенные инструменты и надежную поддержку API, но не заставляет вас их использовать.

2. Встроенная поддержка CSS.

Написание CSS в компонентно-ориентированных фреймворках сопряжено с священной потребностью в «каскаде». Вот почему у вас есть инструменты CSS-in-JS, но Next.js выходит со своим собственным предложением — styled-jsx, а также поддерживает множество методологий стилизации.

3. Автоматическая поддержка TypeScript.

Если вам нравится писать код на TypeScript, с Next.js у вас буквально есть автоматическая поддержка конфигурации и компиляции TypeScript.

4. Техника множественной выборки данных.

Он поддерживает SSG и/или SSR. Вы можете использовать один или другой, или оба.

5. Маршрутизация файловой системы.

Переход с одной страницы на другую поддерживается файловой системой вашего приложения. Вам не нужна специальная библиотека для обработки маршрутизации.

Есть еще много других функций, например, использование экспериментальных функций ES, таких как необязательная последовательность, отсутствие импорта React везде, где вы используете JSX, поддержка API типа next/head, он помогает управлять заголовками HTML-документа и так далее. Достаточно сказать, что чем глубже вы погружаетесь, тем больше вы наслаждаетесь, цените и открываете для себя многие другие функции.

Требования для создания приложения Next.Js.

Для создания приложения Next.js требуется установка Node.js. и утилиты для запуска npm или npx. Чтобы проверить, установлен ли у вас Node.js, запустите команду в своем терминале:

# It should respond with a version number

node v

В идеале npm (и npx) поставляется вместе с установкой Node.js. Чтобы убедиться, что они установлены, выполните команды в терминале:

# Run this. It should respond with a version number

npm v

# Then run this. It should also respond with a version number

npx v

Если ни одна из вышеперечисленных команд не отвечает с номером версии, вы можете изучить порядок установки Node.js и npm. Если вы предпочитаете менеджер пакетов yarn, вы можете запустить его с помощью команды:

# Installs yarn globally

npm i g yarn

Затем подтвердите установку с помощью:

# It should also respond with a version number

yarn v

Создание приложения Next.Js

Выполнив указанные выше требования, создать Next.js можно двумя способами, первый из них более простой: c помощью create-next-app или вручную.

Создание приложения Next.js c помощью Create-next-app.

Использовать create-next-app просто и понятно, к тому же вы также можете использовать стартер, например Next.js с Redux, Next.js с Tailwind CSS или Next.js с Sanity CMS и т. д. Вы можете просмотреть их полный список в примерах Next.js repo.

# Create a new Next.js app with npx

npx createnextapp <appname>

# Create a new Next.js app with npm

npm createnextapp <appname>

# With yarn

yarn create nextapp <appname>

Создание проекта Next.js вручную.

Для этого требуется три пакета: next, react и react-dom.

# With npm

npm install next react reactdom

# With yarn

yarn add next react reactdom

Затем добавьте следующие скрипты в package.json:

«scripts»: {

  «dev»: «next dev»,

  «start»: «next start»,

  «build»: «next build»

}

dev запускает Next.js в режиме разработки.

start запускает Next.js в рабочем режиме.

build создает ваше приложение Next.js для производства.

Структура папок

Одна важная особенность, которую вы можете заметить после создания приложения Next.js — это компактная структура папок. У вас есть минимум для запуска приложения Next.js. Ни больше ни меньше. То, что вы получите по мере роста приложения, зависит от вас больше, чем от фреймворка.

Единственными конкретными папками Next.js являются папки pages, public и styles.

# other files and folders, .gitignore, package.json…

pages

   api

     hello.js

   _app.js

   index.js

public

   favicon.ico

   vercel.svg

styles

   globals.css

   Home.module.css

Страницы

В приложении Next.js страницы — это специфические папки для Next. Вам необходимо знать некоторые вещи о страницах. Страницы — это компоненты React. Каждый файл в нем — это страница, а каждая страница — это компонент React.

// Location: /pages/homepage.js

// <HomePage/> is just a basic React component

export default HomePage() {

  return <h1>Welcome to Next.js</h1>

}

Пользовательские страницы — это специальные страницы с префиксом подчеркивания, например _app.js.

_app.js: Это пользовательский компонент, который находится в папке страниц. Next.js использует этот компонент для инициализации страниц.

_document.js: типа _app.js, _document.js — это специальный компонент, который Next.js использует для расширения тегов html и body ваших приложений. Это необходимо, потому что страницы Next.js пропускают определённую разметку среды документа.

Файловая система маршрутизации на основе страниц.

Next.js имеет файловую систему маршрутизации, где каждая страница автоматически становится маршрутом в зависимости от имени файла. Например, страница по адресу pages/profile будет расположена по адресу /profile, а pages/index.js по адресу /.

# Other folders

pages

   index.js # located at /

   profile.js # located at /profile

   dashboard

     index.js # located at /dashboard

     payments.js # located at /dashboard/payments

Маршрутизация

Next.js имеет файловую систему маршрутизации на основе страниц. Каждая созданная страница автоматически становится маршрутом. Например, pages/books.js станет маршрутом /book.

pages

   index.js # url: /

   books.js # url: /books

   profile.js # url: /profile

Маршрутизация привела к созданию таких библиотек, как React Router. Она может быть пугающей и довольно сложной из-за огромного количества способов, которые вы можете посчитать подходящими для маршрутизации раздела страниц в приложении Next.js. Говорить о маршрутизации в Next.js довольно просто. По большей части, файловая система маршрутизации может использоваться для определения наиболее распространенных шаблонов маршрутизации.

Индексные маршруты

В папке pages автоматически создается страница index.js которая перенаправляется в начальную точку вашего приложения /. У вас могут быть разные index.js страницы, но по одной в каждой папке. Вам не обязательно это делать, но это помогает определить начальную точку ваших маршрутов и избежать некоторой избыточности в именах. Возьмем, к примеру, эту структуру папок:

pages

   index.js

   users

     index.js

     [user].js

Есть два индексных маршрута / и /users. В папке users можно назвать индексный маршрут users.js. Тогда его путь будет /users/users, если это удобно для чтения. В противном случае вы можете использовать индексный маршрут.

Вложенные каталоги

Чтобы структурировать папку, и иметь такой маршрут, как /dashboard/user/:id, вам нужны вложенные папки:

pages

   index.js

   dashboard

     index.js

     user

       [id].js # dynamic id for each user

Вы можете создавать много каталогов и углубляться сколько угодно.

Сегменты динамического маршрута

Сегменты URL-адреса не всегда определенны. Иногда просто невозможно сказать, что будет в процессе разработки. Именно здесь на помощь приходят сегменты динамического маршрута. В последнем примере :id является динамическим сегментом в URL-адресе /dashboard/user/:id. id определяет пользователя, который будет находиться на странице в данный момент. Если вы можете подумать об этом, скорее всего, вы сможете создать его с помощью файловой системы.
Динамическая часть может появляться в любом месте вложенных маршрутов:

pages

   dashboard

     user

       [id].js

           profile

Данный пример предоставляет путь /dashboard/user/:id/profile, который ведет к странице профиля пользователя с определенным идентификатором.

Представьте, как получить доступ к маршруту /news/:category/:category-type/:league/:team, где category, category-type, league и team являются динамическими сегментами. Каждый сегмент будет файлом, и файлы не могут быть вложенными. Здесь вам понадобятся универсальные маршруты, в которых вы распределяете динамические части, например:

pages

   news

     [...id].js

Тогда вы можете получить доступ к маршруту, например /news/sport/football/epl/liverpool. Вам может быть интересно, как получить динамические сегменты в компонентах. Для этой цели предназначен анкор useRouter, экспортируемый из next/router. Он открывает объект router.

import { useRouter } from ‘next/router’;

export default function Post() {

  // useRouter returns the router object

  const router = useRouter();

  console.log({ router });

  return <div> News </div>;

}

Динамические сегменты находятся в свойстве query объекта router, доступ к которому осуществляется с помощью router.query. Если запросов нет, свойство запроса возвращает пустой объект.

Ссылки между страницами

Перемещение между страницами в приложениях может выполняться с помощью компонента Link, экспортированного с помощью next/link. Скажем, у вас есть страницы:

pages

   index.js

   profile.js

   settings.js

   users

     index.js

     [user].js

Вы можете использовать Link:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

import Link from «next/link»;

export default function Users({users) {

  return (

    <div>

      <Link href=«/»>Home</Link>

      <Link href=«/profile»>Profile</Link>

      <Link href=»/settings«>

        <a> Settings </a>

      </Link>

      <Link href=»/users«>

        <a> Settings </a>

      </Link>

      <Link href=»/users/bob«>

        <a> Settings </a>

      </Link>

    </div>

  )

}

Компонент Link имеет ряд допустимых свойств, href — URL-адрес гиперссылки — является единственным необходимым. Он эквивалентен атрибуту href элемента HTML anchor (<a>). Другие свойства включают:

Свойство: as. Значение по умолчанию: такое же как href. Описание: указывает, что отображать в адресной строке браузера.

JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Узнать подробнее

Свойство: passHref. Значение по умолчанию: false. Описание: заставляет компонет Link передать свойство href своему дочернему элементу.

Свойство: prefetch. Значение по умолчанию: true. Описание: позволяет Next.js заблаговременно получать страницы, которые в настоящее время находятся в области просмотра, даже до их посещения, для более быстрого перехода между ними.

Свойство: replace. Значение по умолчанию: false. Описание: заменяет текущую историю переходов вместо того, чтобы помещать новый URL-адрес в стек истории.

Свойство: scroll. Значение по умолчанию: true. Описание: после перехода новая страница должна быть прокручена вверх.

Свойство: shallow. Значение по умолчанию: false. Описание: обновляет путь текущей страницы без повторного запуска getStaticProps, getServerSideProps или getInitialProps, позволяет странице иметь устаревшие данные, если они включены.

Стили

Next.js поставляется с тремя стандартными методами стилизации, глобальным CSS, модулями CSS и styled-jsx.

Линтинг и форматирование

Линтинг и форматирование, я подозреваю, это очень сложная тема, но эмпирические данные показывают, что большинство людей, которые нуждаются в этом в JavaScript, кажется, наслаждаются компанией ESLint и Prettier. Если последний идеально форматирует, то первый выравнивает вашу кодовую базу. Я привык к ESLint и Prettier Setup Уэса Боса, потому что он расширяет eslint-config-airbnb, интерполирует более красивое форматирование через ESLint, включает разумные значения по умолчанию, которые в основном подходят (для меня) и может быть отключен, если возникнет необходимость.

Включить его в проект Next.js довольно просто. Вы можете установить его глобально, если хотите, но мы будем делать это локально. Выполните приведенную ниже команду в терминале.

# This will install all peer dependencies required for the package to work

npx installpeerdeps dev eslintconfigwesbos

Создайте файл .eslintrc в корневом каталоге приложения Next.js, наряду с папками pages, styles и public с содержимым:

{

  «extends»: [

    «wesbos»

  ]

}

На этом этапе вы можете либо выполнить линтинг и форматирование кода вручную, либо позволить редактору взять на себя управление. Для линтинга и форматирования вручную требуется добавить два скрипта npm — lint и lint:fix.

«scripts»: {

  «dev»: «next dev»,

  «build»: «next build»,

  «start»: «next start»

  «lint»: «eslint .», # Lints and show you errors and warnings alone

  «lint:fix»: «eslint . —fix» # Lints and fixes

},

Если вы используете VSCode и предпочитаете, чтобы ваш редактор автоматически проверял и форматировал код, вам необходимо сначала установить плагин ESLint VSCode, а затем добавить следующие команды в настройки VSCode:

# Other setting

«editor.formatOnSave»: true,

«[javascript]»: {

  «editor.formatOnSave»: false

},

«[javascriptreact]»: {

  «editor.formatOnSave»: false

},

«eslint.alwaysShowStatus»: true,

«editor.codeActionsOnSave»: {

  «source.fixAll»: true

},

«prettier.disableLanguages»: [«javascript», «javascriptreact»],

Со временем вам, скорее всего, потребуется переопределить некоторую конфигурацию, например, мне пришлось отключить правило response/jsx-props-no-spreading, которое выводит ошибки, когда свойства JSX распространяются, как в случае pageProps, пользовательского компонента страницы _app.js.

function MyApp({ Component, pageProps }) {

  return <Component {...pageProps} />;

}

Отключение правила происходит следующим образом:

{

  «extends»: [

    «wesbos»

  ],

  «rules»: {

    «react/jsx-props-no-spreading»: 0

  }

}

Статические файлы

На некоторых или нескольких этапах жизненного цикла вашего приложения Next.js вам понадобятся какие-либо файлы. Это могут быть иконки, собственные шрифты, изображения и т.д. В Next.js это называется Обслуживание статических файлов и есть единственный источник для них – папка public. Документация Next.js предупреждают: не называйте каталог public иначе. Его имя нельзя изменять, и это единственный каталог, используемый для обслуживания статических ресурсов.

Доступ к статическим файлам прост. Возьмем, к примеру, структуру папок ниже.

pages

  profile.js

public

   favicon.ico #url /favicon.ico

   assets

     fonts

       fontx.woff2

       fontx.woff # url: /assets/fonts/font-x.woff2

     images

       profileimg.png # url: /assets/images/profile-img.png

styles

   globals.css

Вы можете получить доступ к изображению profile-img.png из компонента <Profile/>:

// <Profile/> is a React component

export default function Profile() {

  return {

      <div className=«profile-img__wrap»>

        <img src=«/assets/images/profile-img.png» alt=«a big goofy grin» />

      </div>

  }

}

или к шрифтам в папке fonts из CSS:

/* styles/globals.css */

@font-face {

  font-family: ‘font-x’;

  src: url(/assets/fonts/font-x.woff2) format(‘woff2’),

       url(/assets/fonts/font-x.woff) format(‘woff’);

}

Получение данных

Получение данных в Next.js — это огромная тема, требующая определенного уровня подготовки. Здесь мы обсудим суть. Прежде чем мы погрузимся в подробности, необходимо сначала понять, как Next.js отображает страницы.
Предварительный рендеринг — важная часть того, как работает Next.js, а также то, что делает его быстрым. По умолчанию Next.js выполняет предварительный рендеринг каждой страницы, заранее генерируя HTML- код каждой страницы вместе с минимальным кодом JavaScript, который необходимо запустить, с помощью процесса, известного как Hydration.

Можно отключить JavaScript, хоть это и непрактично, но при этом некоторые части вашего приложения Next.js будут отображаться. Это можно сделать только из механических соображений, чтобы показать, что Next.js действительно гидрирует отображаемые страницы.

При этом существует две формы предварительного рендеринга: 1) Статическая генерация (SG), 2) Отрисовка на сервере (SSR).

Разница между ними заключается в извлечении данных. Для SG данные извлекаются во время сборки и повторно используются при каждом запросе (что делает его быстрее, поскольку его можно кэшировать), тогда как в SSR данные выбираются при каждом запросе.

Что у них общее, так это то, что их можно совмещать с рендерингом на стороне клиента с помощью fetch, Axios, SWR, React Query и т.д.

Две формы предварительного рендеринга не являются абсолютно взаимоисключающими; вы можете выбрать использование статической генерации или серверный рендеринг, или вы можете их совмещать. То есть, в то время как некоторые части вашего приложения Next.js используют статическую генерацию, другие могут использовать SSR.

В обоих случаях Next.js предлагает специальные функции для получения данных. Вы можете использовать один из традиционных подходов к извлечению данных в React или специальные функции. Желательно использовать специальные функции не потому, что они предположительно особенные, и не потому, что они правильно названы (как вы увидите), а потому, что они дают вам централизованный и привычный метод выборки данных, с которым вы не ошибетесь.

Три специальные функции:

getStaticProps — используется в SG, когда содержимое страницы зависит от внешних данных.

getStaticPaths — используется в SG, когда пути к страницам зависят от внешних данных.

getServerSideProps — используется в рендеринге на стороне сервера.

getStaticProps

getStaticProps является родственным getStaticPaths и используется в Static Generation. Это асинхронная функция, с помощью которой вы можете извлекать внешние данные и возвращать их в качестве поддержки для компонента по умолчанию на странице. Данные возвращаются как объект props и неявно сопоставляются со свойством компонента экспорта по умолчанию на странице.

В приведенном ниже примере нам нужно сопоставить учетные записи и отобразить их. Содержимое страницы зависит от внешних данных, которые мы извлекаем и применяем getStaticProps.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

// accounts get passed as a prop to <AccountsPage/> from getStaticProps()

// Much more like <AccountsPage {…{accounts}} />

export default function AccountsPage({accounts}) {

  return (

    <div>

      <h1>Bank Accounts</h1>

      {accounts.map((account) => (

        <div key={account.id}>

          <p>{account.Description}</p>

        </div>

      ))}

    </div>

  )

}

export async function getStaticProps() {

  // This is a real endpoint

  const res = await fetch(‘https://sampleapis.com/fakebank/api/Accounts’);

  const accounts = await res.json();

  return {

    props: {

      accounts: accounts.slice(0, 10),

    },

  };

}

Как видите, getStaticProps работает со статической генерацией и возвращает объект props, отсюда и название.

getStaticPaths

Подобно getStaticProps, getStaticPaths используется в статической генерации, но отличается тем, что это пути к страницам, которые являются динамическими, а не содержимым страницы. Это часто используется с getStaticProps, потому что он не возвращает никаких данных самому компоненту, вместо этого он возвращает пути, которые должны быть предварительно отрисованы во время сборки. Зная пути, вы можете продолжить получение соответствующего содержимого страницы.

Подумайте о предварительном рендеринге страницы Next.js в аспекте динамической страницы в отношении статической генерации. Чтобы он мог это сделать успешно во время сборки, он должен знать, каковы пути к страницам. Но это невозможно, потому что они динамичны и неопределенны, вот тут-то и нужно getStaticPaths.

Представьте, у вас есть приложение Next.js со страницами States и state, которые отображают список штатов в Соединенных Штатах и все государство соответственно. У вас может быть структура папок, которая выглядит так:

pages

   index.js

   states

     index.js # url: /states

     [id].js # url /states/[id].js

Вы создаете, [id].js чтобы показать одно состояние на основе их id. Таким образом, содержимое страницы (возвращаемые данные getStaticProps) будет зависеть от путей к страницам (возвращаемых данных getStaticPaths). Сначала создадим компоненты <States/>.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

// The states will be passed as a prop from getStaticProps

export default function States({states}) {

  // We’ll render the states here

}

export async function getStaticProps() {

  // This is a real endpoint.

  const res = await fetch(`https://sampleapis.com/the-states/api/the-states`);

  const states = await res.json();

  // We return states as a prop to <States/>

  return {

    props: {

      states

    }

  };

}

Теперь давайте создадим динамическую страницу для одного состояния. Это причина, по которой у нас есть [id].js, чтобы мы могли сопоставить путь /states/1, или /states/2 где 1 и 2 — это id в [id].js.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

// We start by expecting a state prop from getStaticProps

export default function State({ state }) {

    // We’ll render the states here

}

// getStaticProps has a params prop that will expose the name given to the

// dynamic path, in this case, `id` that can be used to fetch each state by id.

export async function getStaticProps({ params }) {

  const res = await fetch(

    `https://sampleapis.com/the-states/api/the-states?id=${params.id}`

  );

  const state = await res.json();

  return {

    props: {

      state: state[0]

    }

  };

}

Если вы попытаетесь запустить код как есть, вы получите сообщение: Error: getStaticPaths is required for dynamic SSG pages and is missing for /states/[id].

// The state component

// getStaticProps function

// getStaticPaths

export async function getStaticPaths() {

  // Fetch the list of states

  const res = await fetch(«https://sampleapis.com/the-states/api/the-states»);

  const states = await res.json();

  // Create a path from their ids: `/states/1`, `/states/2` …

  const paths = states.map((state) => `/states/${state.id}`);

  // Return paths, fallback is necessary, false means unrecognize paths will

  // render a 404 page

  return { paths, fallback: false };

}

С помощью paths возвращенного от getStaticPaths, getStaticProps будет известно и его params параметры будут заполнены необходимыми значениями, как и id в этом случае.

Дополнения

Абсолютный импорт

Начиная с Next.js 9.4 поддерживается абсолютный импорт, что означает, что вам больше не нужно импортировать такие компоненты, как:

import FormField from «../../../../../../components/general/forms/formfield»

вместо этого вы можете сделать это абсолютно так:

import FormField from «components/general/forms/formfield»;

Чтобы это работало, вам понадобится файл jsconfig.json или tsconfig.json для JavaScript и TypeScript соответственно со следующим содержимым:

{

  «compilerOptions»: {

      «baseUrl»: «.»

  }

}

Это предполагает, что папка components существует в корне вашего приложения вместе с pages, styles и public.

Экспериментальные функции ES

В приложении Next.js можно использовать некоторые экспериментальные функции, такие как Оператор нулевого объединения (??) и Оператор опциональной цепочки (?.).

export default function User({user) {

  return <h1>{person?.name?.first ?? ‘No name’}</h1>

}

Заключение

По словам команды Next.js, многие из целей, которые они поставили перед собой, были перечислены в «7 принципах создания полнофункциональных веб-приложений», и по мере того, как вы продвигаетесь в экосистеме и вглубь ее, вы поймете, что вы в надежных руках, как и многие другие пользователи, которые решили использовать Next.js для работы своих веб-сайтов / веб-приложений. Попробуйте, и после этого примите решение.

Автор: Adebiyi Adedotun

Источник: www.smashingmagazine.com

Редакция: Команда webformyself.

JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

Узнать подробнее

Хотите узнать, что необходимо для создания сайта?

Посмотрите видео и узнайте пошаговый план по созданию сайта с нуля!

Смотреть

This article is originally posted at Link

In the last article, we learn how to use getStaticProps() in the Next.js application. In Next.js, we can pre-render a page during build time. We generate all the HTML code and data in advance. And the data is later cached by the server.

This approach works well for the static paths but, it fails when we have to pre-render pages for dynamic paths. And it makes sense. Let’s say there is a blog and, there are multiple articles under it. And it next.js we defined dynamic paths like [blogId].js. As we already know, this path is valid for blog id 1, 2, 3, 4, and so on. There is no way Next.js knows how many pages it has to render.

To accomplish this, getStaticPath() is another function we use in this article.

To create the Next.js app, please follow this article.

Let’s add a directory named blog under the pages folder. And add another route [blogId].js under the blog directory.

Just to start with, please add the following code:

function getBlogIdDetails(props){
    return (
        <div>
            Blog ID details pages
        </div>
    )
}

export  default getBlogIdDetails

Visit the URL, http://localhost:3000/blog/1 and, you will see «Blog ID details pages» on the browser.

Now create another file next.config.js and add the following:

module.exports = {
    webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
        config.node = {
            fs: 'empty', // This is required
        }
        return config
    }
}

Save the previous and create another file blogs_details.json and add the following content:

{

  "blogs": [

    { "id": "1", "title": "My First Blog", "description": "This is the content of first blog" },

    { "id": "2", "title": "My Second Blog", "description": "This is the content of second blog" },

    { "id": "3", "title": "My Third Blog", "description": "This is the content of third blog" },

    { "id": "4", "title": "My Fourth Blog", "description": "This is the content of fourth blog" },

    { "id": "5", "title": "My Fifth Blog", "description": "This is the content of fifth blog" },

    { "id": "6", "title": "My Sixth Blog", "description": "This is the content of sixth blog"}

  ]

}

The above file is our backend file, which we read using Next.js (Remember getStaticProps) and then dynamically load into our app.

Update the contents of the file [blogid].js

function getBlogIdDetails(props){
    return (
        <div>
            <h1><strong>{props.blogDetails.title} </strong> </h1>
            <br/>
            <p>{props.blogDetails.description}</p>
        </div>
    )
}

export async function getStaticProps() {
    return {
        props: {
            blogs: [{id: '1', title: 'title1'}, {id: '2', title: 'title2'}, {id: '3', title: 'title3'}]
        },
    };
}

export  default getBlogIdDetails

And now refresh the page «http://localhost:3100/blog/1».

At this point, you will see ‘Error: getStaticPaths is required for dynamic SSG pages’

Remember we discussed how getStaticProps() fails in dynamic paths.

Let’s get started with getStaticPaths().

Open the file [blogid.js] and import the following:

import fs from 'fs'
import path from 'path'

We need to import fs (to read the file) and path (To get the current working directory function) from node.js.
and then update the getStaticProps() function with:

export async function getStaticProps(context) {
    const { params } = context
    const blogId = params.blogid
    const fileToRead = path.join(process.cwd(), 'blogs_details.json')
    const data = JSON.parse(await fs.readFileSync(fileToRead))
    const blog = data.blogs.find(blog => blog.id === blogId)
    return {
        props: {
            blogDetails: blog
        },
    };
}

And add the function getStaticPaths() afterwards

export async function getStaticPaths() {
    return {
        paths: [
            {  params: { blogid: '1' } },
            {  params: { blogid: '2' } },
            {  params: { blogid: '3' } },
        ],
        fallback: false
    }
}

The getStaticPaths() function tells the Next.js to render the pages defined in paths. This function always returns the object.

Also, don’t forget to add the fallback keyword to the getStaticPaths() function.

The complete file will look like

import fs from 'fs'
import path from 'path'
function getBlogIdDetails(props){
    return (
        <div>
            <h1><strong>{props.blogDetails.title} </strong> </h1>
            <br/>
            <p>{props.blogDetails.description}</p>
        </div>
    )
}
export async function getStaticProps(context) {
    const { params } = context
    const blogId = params.blogid
    const fileToRead = path.join(process.cwd(), 'blogs_details.json')
    const data = JSON.parse(await fs.readFileSync(fileToRead))
    const blog = data.blogs.find(blog => blog.id === blogId)
    return {
        props: {
            blogDetails: blog
        },
    };
}
export async function getStaticPaths() {
    return {
        paths: [
            {  params: { blogid: '1' } },
            {  params: { blogid: '2' } },
            {  params: { blogid: '3' } },
        ],
        fallback: false
    }
}
export  default getBlogIdDetails

The fallback can help us if we have too many blogs in our app, which is quite normal. A blog has 100s or 1000s of articles and it is not a good idea to pre-generate all those pages in advance. We don’t want to pre-generate pages for the year-old blogs or the blogs which are not read enough by the users.

In that case, we set the fallback to true and delete all the other pages from the returned object. In our case let say, we don’t want to pre-generate blog 2 and blog 3 pages.

export async function getStaticPaths() {
    return {
        paths: [
            {  params: { blogid: '1' } }
        ],
        fallback: true
    }
}

And also update the function getBlogIdDetails

function getBlogIdDetails(props){
    const { blogDetails } = props;
    // This will return Loading and prevents the page from being crashed    
    if (!blogDetails ) {
        return <p>Loading....</p>
    }

    return (
        <div>
            <h1><strong>{props.blogDetails.title} </strong> </h1>
            <br/>
            <p>{props.blogDetails.description}</p>
        </div>
    )
}

The above code will only pre-generate the pages for blog 1. Though all the paths to the blogs are still valid.

Thanks for reading up to here. Will see you in the next article.

I have an edit page that will be rendered with an id parameter and it works fine when application is running but while building the nextjs app I get this error

[Error: ENOENT: no such file or directory, rename ‘C:UsersAhsan NisarDocumentsGitHubcustomer-portalfrontend.nextexportencompaniesedit[id].html’ -> ‘C:UsersAhsan NisarDocumentsGitHubcustomer-portalfrontend.nextserverpagesencompaniesedit[id].html’]

the full error

I am not sure what this error is related to or what mistake am I making in my code that this error is occuring during build time.

Here is the code of my page

import { WithAuthorization } from 'common/roq-hocs';
import { MainLayout } from 'layouts';
import { useTranslation } from 'next-i18next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import React, { FunctionComponent } from 'react';
import { CompaniesEditView } from 'views/companies-edit';

const CompanyCreatePage: FunctionComponent = () => {
  const { t } = useTranslation('companiesEdit');
  return (
    <MainLayout title={t('title')}>
      <WithAuthorization
        permissionKey="companies.update"
        failComponent={
          <div className="mt-16 text-2xl text-center text-gray-600">
            <span>{t('noView')}</span>
          </div>
        }
      >
        <CompaniesEditView />
      </WithAuthorization>
    </MainLayout>
  );
};

export const getStaticProps = async ({ locale }) => ({
  props: {
    ...(await serverSideTranslations(locale, ['common', 'companiesEdit'])),
  },
});

export const getStaticPaths = () => ({
  paths: ['/companies/edit/[id]'],
  fallback: true,
});

export default CompanyCreatePage;

I am getting this error "Error: getStaticPaths is required for dynamic SSG pages and is missing for 'xxx'" when I try to create my page in NextJS.

I don’t want to generate any static page on build time. So why do I need to create a 'getStaticPaths' function?

4 Answers

If you are creating a dynamic page eg: product/[slug].tsx then even if you don’t want to create any page on build time you need to create a getStaticPaths method to set the fallback property and let NextJS know what to do when the page you are trying to get doesn’t exist.

export const getStaticPaths: GetStaticPaths<{ slug: string }> = async () => {

    return {
        paths: [], //indicates that no page needs be created at build time
        fallback: 'blocking' //indicates the type of fallback
    }
}

getStaticPaths does mainly two things:

  • Indicate which paths should be created on build time (returning a paths array)

  • Indicate what to do when a certain page eg: «product/myProduct123» doesn’t exist in the NextJS Cache (returning a fallback type)

Dynamic Routing Next Js

pages/users/[id].js

import React from 'react'

const User = ({ user }) => {
  return (
    <div className="row">
      <div className="col-md-6 offset-md-3">
        <div className="card">
          <div className="card-body text-center">
            <h3>{user.name}</h3>
            <p>Email: {user.email} </p>
          </div>
        </div>
      </div>
    </div>
  )
}

export async function getStaticPaths() {
  const res = await fetch('https://jsonplaceholder.typicode.com/users')
  const users = await res.json()

  const paths = users.map((user) => ({
    params: { id: user.id.toString() },
  }))

  return { paths, fallback: false }
}


export async function getStaticProps({ params }) {
  const res = await fetch(`https://jsonplaceholder.typicode.com/users/${params.id}`)
  const user = await res.json()

  return { props: { user } }
}

export default User

if you are using getStaticPaths, you are telling next.js that you want to pregenerate that page. However since you used it inside a dynamic page, next.js does not know in advance how many pages it has to create.

with getStaticPaths, we fetch the database. If we are rendering blogs, we fetch the database to decide how many blogs we have, what would be idOfBlogPost and then based on this information, getStaticPath will pre-generate pages.

also, getStaticProps does not run only during the build time. If you add revalidate:numberOfSeconds, next.js will recreate new page with fresh data after «numberOfSeconds» time.

For rendering dynamic route use getServerSideProps() instead of getStaticProps()

For Example:

export async function getServerSideProps({
locale,
}: GetServerSidePropsContext): Promise<GetServerSidePropsResult<Record<string, unknown>>> {

return {
    props: {
        ...(await serverSideTranslations(locale || 'de', ['common', 'employees'], nextI18nextConfig)),
    },
  }
}

You can check here as well

Понравилась статья? Поделить с друзьями:
  • Error getaddrinfo enotfound postgres
  • Error getaddrinfo enotfound localhost
  • Error getaddrinfo enotfound api postman
  • Error get version перевод
  • Error get response code 500 try later