javascript - 如何从 JSON 文件在 Gatsby 中创建页面?

标签 javascript reactjs gatsby react-context

我正在尝试使用 JSON 文件在 Gatsby 中动态创建页面。在该文件中,我定义了应该在页面中呈现的组件。

我遵循了 Gatsby 的文档,但是它没有我想要的。因此,我尝试通过读取 JSON 文件并遍历其中的组件并使用 React.createElement() 创建它们来创建页面。最后,我得到了一个 React 组件数组,我将其传递给模板页面组件的 createPage 方法的上下文对象中的 Children 属性。

这是解决这个想法的正确方法吗?这在 Gatsby 中可行吗?

我认为说我尝试过动态导入并且效果很好是有用的,但我正在尝试找到一种不必将所有组件转储到一个文件夹中的方法。

我有这个项目的 Github 存储库。 https://github.com/ahmedalbeiruti/Gatsby-dynamic-pages

这是代码的主要部分:

gatsby-node.js

exports.createPages = ({actions})=>{
    const {createPage} = actions
    const resutl = componentsRenderer(data.page.layout.columns)
    createPage({
        path: data.page.name,
        component: path.resolve('./src/template/page.js'),
        context:{
            children: resutl
        }
    })
}

const componentsRenderer = components => {

    return components.map(component => {
        let children = []
        if (component.children){
            children = componentsRenderer(component.children)
        }
        const element = require(`${__dirname}/${component.path}`)

        return React.createElement(element, Object.assign({},{key: component.key},{...component.props}),children)
    });
}

数据/sample-page-no-props.json

{
        "page":{
            "name": "about",
            "layout":{
                "columns": [
                    {
                        "key":"column_1",
                        "name": "Column",
                        "path": "/src/components/layouts/column.jsx",
                        "children":[
                            {
                                "name": "FirstComponent",
                                "path": "/src/components/custom/first-component.jsx",
                                "key": "first_component_1"
                            }
                        ]
                    },
                    {
                        "key": "column_2",
                        "name": "Column",
                        "path": "/src/components/layouts/column.jsx",
                        "children":[
                            {
                                "key": "second_component_1",
                                "name": "SecondComponent",
                                "path": "/src/components/custom/second-component.jsx",
                                "children":[
                                    {
                                        "key": "leaf_component_1",
                                        "name": "LeafComponent",
                                        "path":"/src/components/custom/leaf-component.jsx"
                                    }
                                ]
                            },
                            {
                                "key": "third_component_1",
                                "name": "ThirdComponent",
                                "path": "/src/components/custom/third-component.jsx",
                                "children":[
                                    {
                                        "key": "leaf_component_1",
                                        "name": "LeafComponent",
                                        "path":"/src/components/custom/leaf-component.jsx"
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        }
}

data/sample-page-with-style-prop.json(FirstComponent 有 props 对象)

{
        "page":{
            "name": "about",
            "layout":{
                "columns": [
                    {
                        "key":"column_1",
                        "name": "Column",
                        "path": "/src/components/layouts/column.jsx",
                        "children":[
                            {
                                "name": "FirstComponent",
                                "path": "/src/components/custom/first-component.jsx",
                                "key": "first_component_1",
                                "props":{
                                    "style":{
                                        "color":"red"
                                    }
                                }
                            }
                        ]
                    },
                    {
                        "key": "column_2",
                        "name": "Column",
                        "path": "/src/components/layouts/column.jsx",
                        "children":[
                            {
                                "key": "second_component_1",
                                "name": "SecondComponent",
                                "path": "/src/components/custom/second-component.jsx",
                                "children":[
                                    {
                                        "key": "leaf_component_1",
                                        "name": "LeafComponent",
                                        "path":"/src/components/custom/leaf-component.jsx"
                                    }
                                ]
                            },
                            {
                                "key": "third_component_1",
                                "name": "ThirdComponent",
                                "path": "/src/components/custom/third-component.jsx",
                                "children":[
                                    {
                                        "key": "leaf_component_1",
                                        "name": "LeafComponent",
                                        "path":"/src/components/custom/leaf-component.jsx"
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        }
}

模板/page.js

import React from 'react'
import Layout from '../components/layouts/Layout'

const Page = (props)=>{
    console.log(`page_context: ${props.pageContext.children}`)
    return (
        <>
        <h1>this is the about page</h1>
        <Layout>
            {props.pageContext.children}
        </Layout>
        </>
    )
}

export default Page

组件/自定义/first-component.jsx

// import React from "react";

const React = require("react");

module.exports = (props)=>{
    return(
        <h3 style={props.style}>
            Hi this is the first component
        </h3>
    )
}

// export default FirstComponent

使用sample-page-with-style-prop.json 文件时遇到的错误如下:

UNHANDLED REJECTION Cannot assign to read only property 'style' of object '#<Object>'

TypeError: Cannot assign to read only property 'style' of object '#<Object>'

如果我更改为sample-page-no-props.json 文件,我会收到以下错误:

UNHANDLED REJECTION Cannot assign to read only property 'children' of object '#<Object>'

TypeError: Cannot assign to read only property 'children' of object '#<Object>'

最佳答案

而不是将组件作为上下文传递给页面模板。正确的方法是传递数据并在页面内渲染组件

gatsby-node.js

exports.createPages = ({actions})=>{
    const {createPage} = actions
    const resutl = componentsRenderer(data.page.layout.columns)
    createPage({
        path: data.page.name,
        component: path.resolve('./src/template/page.js'),
        context:{
            children: resutl
        }
    })
}

template/page.js

import React from 'react'
import Layout from '../components/layouts/Layout'

const componentsRenderer = components => {

    return components.map(component => {
        let children = []
        if (component.children){
            children = componentsRenderer(component.children)
        }
        const element = require(`${HOME_DIR}/${component.path}`)

        return React.createElement(element, Object.assign({},{key: component.key},{...component.props}),children)
    });
}
const Page = (props)=>{
    const data = props.pageContext.children
    return (
        <>
        <h1>this is the about page</h1>
        <Layout>
            {componentsRenderer(data)}
        </Layout>
        </>
    )
}

export default Page

PS:确保页面组件中的HOME_DIR路径正确。

关于javascript - 如何从 JSON 文件在 Gatsby 中创建页面?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57264220/

相关文章:

javascript - 如何在 JavaScript 中关联两个输入?

javascript - 如何在 React 中使用 Tailwindcss 转换 div

reactjs - `eval()` ing 带有 JSX 语法的代码

javascript - Netlify 未检测到 GatsbyJS 表单

reactjs - 使用 React 和 TS 将 PageProps 从 Gatsby 和 Parent 传递到功能组件返回未定义

javascript - 跨域发送sessionToken

javascript - 禁用和启用 ng-repeat 中的按钮

javascript - 谷歌计划 : Polymer & Angular

javascript - 捕获到具有错误边界的错误后,如何使用react-router?

javascript - Gatsby : Display 404 page if route doesn't exist