首页 > 解决方案 > Nextjs getStaticProps 未触发

问题描述

下面我的 [slug].js 文件有两个 nextjs 辅助函数。getStaticPaths 和 getStaticProps 被导出。就我而言,它创建了路径posts/[slug]。添加了一个名为hello.json. 现在当我导航到localhost:3000/posts/hello它错误说:

TypeError: Cannot read property 'fileRelativePath' of undefined. 对于第 10 行。

jsonFile在看到未定义之后,这是有道理的。事实上,getStaticProps从不调用整体,从不记录那里的登录。为什么会这样?

提前致谢。

import React from 'react';
import glob from 'glob';
import { usePlugin } from 'tinacms';
import { useJsonForm } from 'next-tinacms-json';

const Page = ({ jsonFile }) => {
    console.log(121212, jsonFile);

    // Create the tina form
    const [post, form] = useJsonForm(jsonFile);

    // Register it with the CMS
    usePlugin(form);

    return (
        <h1>
            {post.title}
        </h1>
    );
};

export default Page;

/**
 * By exporting the async function called getStaticProps from a page, Next.js
 * pre-renders this page at build time using the props returned by
 * getStaticProps.
 * The getStaticPaths function defines a list of paths that have
 * to be rendered to HTML at build time.
 */

export async function getStaticProps({ ...ctx }) {
    console.log(1212, ctx);
    const { slug } = ctx.params;
    const dynamicPath = `../../posts/${slug}.json`; // for eslint parsing error: "Cannot read property 'range' of null Occurred while linting"
    const content = await import(dynamicPath);

    console.log(121212, content);

    return {
        props: {
            jsonFile: {
                fileRelativePath: `/posts/${slug}.json`,
                data: content.default,
            },
        },
    };
}

export async function getStaticPaths() {
    //get all .json files in the posts dir
    const posts = glob.sync('posts/**/*.json');

    const paths = posts.map(file => ({
        params: {
            slug: `${file.replace('.json', '')}`,
        },
    }));

    return {
        paths,
        fallback: true,
    };
};

标签: javascriptreactjsnext.js

解决方案


经过更多的挖掘,我发现了这个问题,在这里发帖希望能帮助未来的读者解决同样的问题。

罪魁祸首是这样的:

const dynamicPath = `../../posts/${slug}.json`; // for eslint parsing error: "Cannot read property 'range' of null Occurred while linting"
const content = await import(dynamicPath);

在动态导入中使用变量不起作用,只能使用字符串或模板文字。我使用了一个变量,因为 eslint 解析错误只能通过降级到早期版本的 eslint 来解决。这会导致 eslint 在此文件中对我不起作用,但是好的,至少调用了该函数。

这与在调用之前getStaticProps调用组件代码的观察结果相结合,使得 jsonFile 变量未定义,并且整个组件在到达getStaticProps. 您可以看到以 开头的日志121212早于1212. 终端日志:

121212 {
  fileRelativePath: 'posts/hello.json',
  data: { title: 'Not the actual data' }
}
1212 hello

这对我来说是反直觉的,因为我认为它会首先获取道具并立即将它们传递给组件,但遗憾的是,需要定义默认道具来解决这个问题。

新代码:

import React from 'react';
import glob from 'glob';
import { usePlugin } from 'tinacms';
import { useJsonForm } from 'next-tinacms-json';

const Page = ({ jsonFile }) => {
    console.log(121212, jsonFile);

    // Get content and form for Tina
    const [content, form] = useJsonForm(jsonFile);

    // Register it with the CMS
    usePlugin(form);

    return (
        <h1>
            {content.title}
        </h1>
    );
};

Page.defaultProps = {
    jsonFile: {
        fileRelativePath: 'posts/hello.json',
        data: {
            title: 'Not the actual data',
        },
    },
};

export default Page;

/**
 * By exporting the async function called getStaticProps from a page, Next.js
 * pre-renders this page at build time using the props returned by
 * getStaticProps.
 */
export async function getStaticProps({ params: { slug } }) {
    console.log(1212, slug);

    // This line caused the issue
    // const dynamicPath = (`../../posts/${slug}.json`; // for eslint parsing error: "Cannot read property 'range' of null Occurred while linting"
    const content = await import(`../../posts/${slug}.json`);

    return {
        props: {
            jsonFile: {
                fileRelativePath: `posts/${slug}.json`,
                data: content.default,
            },
        },
    };
}

/**
 * The getStaticPaths function defines a list of paths that have
 * to be rendered to HTML at build time.
 */
export async function getStaticPaths() {
    //get all .json files in the posts dir
    const posts = glob.sync('posts/**/*.json');

    return {
        paths: posts.map(file => ({
            params: {
                slug: `${file.replace('.json', '')}`,
            },
        })),
        fallback: true,
    };
}

推荐阅读