如何为Gatsby中的嵌套节点创建Image数据?
问题
我尝试使用createRemoteFileNode为Product节点下的items数组中的节点创建优化图片。我有一个包含items的Product,每个Item都有featuredImg。我可以为Product创建featuredImg,但为子节点(Item)创建时,通过Products.items[i].featuredImg查询始终返回null,不过单独查询item.featuredImg时能正常返回gatsbyImageData。
我的节点创建代码如下:
const products = [ { id: "product_1", imageUrl: "https://images.unsplash.com/photo-1665081661649-8656335a6cbb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1738&q=80", items: [ { id: 'item_1', imageUrl: "https://images.unsplash.com/photo-1666120565124-7e763880444a?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1770&q=80" } ] } ] const sourceNodes = async ({ actions, createNodeId, createContentDigest }, options) => { products.forEach((testNode) => { const node = { ...testNode, id: createNodeId(`Product-${testNode.id}`), } actions.createNode({ ...node, internal: { type: 'Product', contentDigest: createContentDigest(node), }, }); testNode.items.forEach(item => { const itemNode = { ...item, id: createNodeId(`Item-${item.id}`), } actions.createNode({ ...itemNode, parent: node.id, internal: { type: 'Item', contentDigest: createContentDigest(itemNode), }, }); }) }) }; module.exports = sourceNodes;
节点创建时执行的onCreateNode函数:
const { createRemoteFileNode } = require(`gatsby-source-filesystem`); const onCreateNode = async ({ node, cache, store, getCache, actions: { createNode, createNodeField }, createNodeId }) => { if( node.internal.type === 'Item') { const fileNode = await createRemoteFileNode({ url: node.imageUrl, parentNodeId: node.parent, createNode, createNodeId, getCache, }) if (fileNode) { createNodeField({ node, name: "localFile", value: fileNode.id }) } } if( node.internal.type === 'Product') { const fileNode = await createRemoteFileNode({ url: node.imageUrl, parentNodeId: node.id, createNode, createNodeId, getCache, }) if (fileNode) { createNodeField({ node, name: "localFile", value: fileNode.id }) } } }; module.exports = onCreateNode
类型定义:
module.exports = ({ actions }) => { const { createTypes } = actions; const typeDefs = ` type Product implements Node { id: String! imageUrl: String! featuredImg: File @link(from: "fields.localFile") items: [Item] } type Item implements Node { id: String! imageUrl: String! featuredImg: File @link(from: "fields.localFile") } `; createTypes(typeDefs); };
我已找到类似问题,但不知如何将createSchemaCustomization或createResolvers解决方案应用到我的场景中。
解决方案
问题根源在于创建Product节点时,items字段存储的是原始对象数组,而非Gatsby节点引用。Gatsby无法自动关联这些原始对象和后续创建的Item节点,导致嵌套查询时无法找到对应的featuredImg。
方法一:修改节点创建逻辑,通过ID关联父子节点
- 修改
sourceNodes函数,创建Product时不再保留原始items数组,而是存储子Item节点的ID列表:
const sourceNodes = async ({ actions, createNodeId, createContentDigest }, options) => { products.forEach((testNode) => { // 提取item的ID,后续用来关联 const itemIds = testNode.items.map(item => createNodeId(`Item-${item.id}`)); const node = { ...testNode, id: createNodeId(`Product-${testNode.id}`), // 替换原始items为ID数组 itemIds: itemIds, // 删除原始items字段,避免冲突 items: undefined, } actions.createNode({ ...node, internal: { type: 'Product', contentDigest: createContentDigest(node), }, }); testNode.items.forEach(item => { const itemNode = { ...item, id: createNodeId(`Item-${item.id}`), } actions.createNode({ ...itemNode, parent: node.id, internal: { type: 'Item', contentDigest: createContentDigest(itemNode), }, }); }) }) };
- 更新类型定义,用
@link通过itemIds关联到Item节点:
module.exports = ({ actions }) => { const { createTypes } = actions; const typeDefs = ` type Product implements Node { id: String! imageUrl: String! featuredImg: File @link(from: "fields.localFile") itemIds: [String!]! items: [Item] @link(from: "itemIds") } type Item implements Node { id: String! imageUrl: String! featuredImg: File @link(from: "fields.localFile") } `; createTypes(typeDefs); };
方法二:使用createResolvers手动解析Product的items字段
如果不想修改节点创建逻辑,可以通过createResolvers动态获取Product对应的子Item节点:
在gatsby-node.js中添加以下代码:
exports.createResolvers = ({ createResolvers }) => { const resolvers = { Product: { items: { resolve: (source, args, context, info) => { // 查找所有父节点为当前Product的Item节点 return context.nodeModel.runQuery({ query: { filter: { parent: { eq: source.id } } }, type: "Item", firstOnly: false, }) } } } } createResolvers(resolvers) }
这个方法会在查询Product.items时,自动根据父子节点的parent关联关系返回对应的Item节点,嵌套查询items.featuredImg即可正常获取数据。
两种方法任选其一即可解决问题,推荐方法一,逻辑更清晰,性能更优。
内容的提问来源于stack exchange,提问作者Stretch0
相关产品推荐
相关产品推荐

