如何基于Next.js

问题描述

我试图创建一个菜单组件,该组件在构建时读取pages文件夹的内容。但是我没有任何成功。这是我尝试过的:

import path from "path";
import * as ChangeCase from "change-case";

export default class Nav extends React.Component {
    render() {
        return (
            <nav>
                {this.props.pages.map((page) => (
                    <a href={page.link}>{page.name}</a>
                ))}
            </nav>
        );
    }

    async getStaticProps() {
        let files = fs.readdirsync("../pages");
        files = files.filter((file) => {
            if (file == "_app.js") return false;
            const stat = fs.lstatSync(file);
            return stat.isFile();
        });

        const pages = files.map((file) => {
            if (file == "index.js") {
                const name = "home";
                const link = "/";
            } else {
                const link = path.parse(file).name;
                const name = ChangeCase.camelCase(link);
            }
            console.log(link,name);
            return {
                name: name,link: link,};
        });

        return {
            props: {
                pages: pages,},};
    }
}

这不起作用,该组件未收到props页面。我尝试过切换到功能组件,从getStaticProps()返回承诺,切换到getServerSideProps(),并将目录读取代码包含到render方法中。

前两个不起作用,因为除非组件是页面,否则getStaticProps()getServerSideProps()永远不会被调用,并且由于自定义fs以来未定义或导入fs,因此在render方法中包含代码失败代码可能在没有fs访问权限的前端运行。

我还尝试将代码添加getStaticProps()内的_app.js函数中,希望通过上下文将页面推送到组件,但似乎getStaticProps()并没有也可以在那里打电话。

我可以在包含菜单页面的getStaticProps函数中运行代码,但是我必须对每个页面重复此操作。即使我将逻辑提取到从getStaticProps调用的模块中,也是如此:

// ...

export async function getStaticProps() {
    return {
        props: {
            pages: MenuMaker.getPages(),// ...
        }
    }
}

,然后通过布局组件将页面传递到页面内的导航组件:

export default function Page(props) {
    return (
        <Layout pages={props.pages}></Layout>
    )
}

然后,要在网站的每个页面添加很多样板。

当然有更好的方法...不可能没有在构建时将静态数据添加到全局状态的方法,对吗?如何在构建时生成动态菜单

解决方法

我设法通过从next.config.js导出一个函数并设置一个包含菜单结构的环境变量来使其工作。我将菜单加载代码抽象到了它自己的文件中。在看到结果之后,我更好地理解了为什么我找不到一个类似的人的例子:

菜单未按我想要的方式排序。我可以按字母顺序或按修改日期对其进行排序,但实际上,几乎总是需要相对于页面主题手动对其进行排序。我可以使用整数,既可以附加到文件名上,也可以附加到文件中的某个位置(也许在注释行中)。但是回想起来,我认为对组件中的链接进行硬编码毕竟可能是最好的方法,因为它提供了更大的灵活性,即使从长远来看也可能不会做太多的工作。

话虽如此,我正在分享我的解决方案,因为它是初始化应用程序范围内的静态状态的一种方法。这并不理想,如果您希望在此处重新计算变量,则必须重新启动开发服务器,这就是为什么我对其他可能的解决方案仍然感兴趣的原因,但是它确实起作用。所以这里是:

next.config.js

const menu = require("./libraries/menu.js");

module.exports = (phase,{ defaultConfig }) => {
    return {
        // ...
        env: {
            // ...
            menu: menu.get('pages'),// ...
        },// ...
    };
};

libraries / menu.js

const fs = require("fs");
const path = require("path");
const ccase = require("change-case");

module.exports = {
    get: (pagePath) => {
        if (pagePath.slice(-1) != "/") pagePath += "/";
        let files = fs.readdirSync(pagePath);
        files = files.filter((file) => {
            if (file == "_app.js") return false;
            const stat = fs.lstatSync(pagePath + file);
            return stat.isFile();
        });

        return files.map((file) => {
            if (file == "index.js") {
                return {
                    name: "Home";
                    link: "/";
                };
            } else {
                link = path.parse(file).name;
                return {
                    link: link;
                    name: ccase.capitalCase(link);
                };
            }
        });
    },};

然后从可包含在布局中的组件中的环境变量生成实际菜单:

components / nav.js

import Link from "next/link";

export default class Nav extends React.Component {
    render() {
        return (
            <nav>
                {process.env.menu.map((item) => (
                    <Link key={item.link} href={item.link}>
                        <a href={item.link}>
                            {item.name}
                        </a>
                    </Link>
                ))}
            </nav>
        );
    }
}
,

您可以尝试以下方法:

const fg = require('fast-glob');
const pages = await fg(['pages/**/*.js'],{ dot: true });

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...