如何从 JSON 文件在 Gatsby 中创建页面?
Posted
技术标签:
【中文标题】如何从 JSON 文件在 Gatsby 中创建页面?【英文标题】:How to create a page in Gatsby from JSON file? 【发布时间】:2019-12-07 09:45:30 【问题描述】:我正在尝试使用 JSON 文件在 Gatsby 中动态创建一个页面。在该文件中,我定义了应在页面中呈现的组件。
我遵循了 Gatsby 的文档,但是,它没有我想要的。所以我尝试通过读取 JSON 文件并遍历其中的组件并使用 React.createElement() 创建它们来创建页面。最后,我得到了一个 react 组件数组,我将这些组件传递给了模板页面组件的 createPage 方法的 context 对象中的 children prop。
这是解决这个想法的正确方法吗?它在盖茨比中是否可行?
我认为说我尝试了动态导入并且效果很好是很有用的,但我正在尝试找到一种方法,我不必将所有组件转储到一个文件夹中。
我有这个项目的 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"
]
]
]
模板/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】:而不是将组件作为上下文传递给页面模板。正确的方法是传递数据并在 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
路径正确。
【讨论】:
非常感谢您的回复,我正在尝试您的建议。不幸的是,它没有用。我收到错误:元素类型无效:需要一个字符串(对于内置组件)或一个类/函数(对于复合组件),但得到:对象。这可能是因为我没有将要求更改为 es6 导入(实际上是使用可加载组件),但这将使它成为我已经完成的动态导入并且它工作正常。我正在寻找替代方案,因为我的团队选择不进行动态导入。 似乎您应该将组件导出为默认值并导入为默认值,如const element = require(`$HOME_DIR/$component.path`).default
以上是关于如何从 JSON 文件在 Gatsby 中创建页面?的主要内容,如果未能解决你的问题,请参考以下文章
Gatsby:在页面上组合两个 graphql 源(.json 和 .jpg 源)