我正在尝试使用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>'
答案 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
路径正确。