如何通过JSON文件在Gatsby中创建页面?

时间:2019-07-30 04:17:08

标签: javascript reactjs gatsby react-context

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

我遵循了盖茨比的文档,但是,它没有我想要的东西。因此,我尝试通过读取JSON文件并遍历其中的组件并使用React.createElement()创建它们来创建页面。最后,我得到了一系列的反应组件,并将它们传递给模板页面组件的createPage方法的上下文对象中的子对象。

解决这个想法是否正确?可以在盖茨比做到吗?

我认为说动态导入效果很好,但我想找到一种不必将所有组件都转储到一个文件夹中的方法。

我有这个项目的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)
    });
}

data / 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"
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        }
}

template / 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

components / custom / 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>'

1 个答案:

答案 0 :(得分:0)

不是将组件作为上下文传递到页面模板。正确的方法是传递数据并在Page中呈现组件

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路径正确。