Gatsby 具有自己查询的可重用组件

Posted

技术标签:

【中文标题】Gatsby 具有自己查询的可重用组件【英文标题】:Gatsby reusable components with own query 【发布时间】:2018-03-13 04:37:42 【问题描述】:

目前是否可以在 Gatsby 中构建具有自己的 graphql 查询的可重用组件?如果不是,那么目前将数据传递给可重用组件的最“耦合”方式是什么?我似乎找不到任何执行此操作的示例,并且在文档中找不到任何内容。

例如,您想为博客制作一个标签云组件,该组件将显示在所有“帖子”页面的侧边栏中以及单个“/tag-cloud”页面上。您可以使用 <TagCloud limit=20 /><TagCloud tags=uniqueTags />。为此,您需要查询所有边,将每个 tags 数组映射减少/提取到唯一的、有序的唯一标签字符串集。

或者,假设您想要一个排除当前产品的目录页面的“其他产品”组件。在这里,您可能有<ProductsList exclude=currentProduct />。这将是构建时直接过滤的查询。

我能看到这样做的唯一方法是对来自createPages() 的查询结果进行猴子修补,或者通过contextcreatePage(path, component, context) 中传递数据。这应该发生在gatsby-node.js 吗?还有其他方法吗?

【问题讨论】:

快速回答是片段github.com/gatsbyjs/gatsby/… 希望我有时间尽快写下这方面的文档。 感谢@KyleMathews(非常感谢 Gatsby)。完成后我会调查并更新。 @KyleMathews - 仍然没有看到它。片段(在查询中)似乎只接收到它们扩展的单个 graphql 边缘。我没有看到任何可以访问的示例,例如allMarkdownRemark。对于头像示例,作为另一个示例,您将如何在单个帖子页面上显示所有网站作者的所有头像列表?或者,如果我可以在gatsby-node.js 中建立一个列表,我应该如何将它传递给所有页面? 【参考方案1】:

我正在回答我自己的问题。如果有人有更好的解决方案,请提交,我很乐意接受。

我当前的解决方案,我在我的问题中引用并且我认为不是最理想的,是在pages/index.js(或您使用createPage(path, component, context) 的任何地方)构建***可重用组件所需的所有数据并将数据注入context。这使得它可以通过pathContext 属性提供给component 构造函数。名称pathContext 让我觉得这是对这个对象精神的滥用,但它完成了工作。

例如,如果您有一个博客,其条目可能有一组标签,这可能是您的gatsby-node.js

const path = require('path');

const getUniqueTags = edges => 
    const set = new Set();

    edges.forEach(edge => edge.node.frontmatter.tags.forEach(tag => set.add(tag)));

    return [...set];
;

exports.createPages = ( graphql, boundActionCreators ) => resolve(graphql(`
        query AllPagesQuery 
            allMarkdownRemark 
                edges 
                    node 
                        frontmatter 
                            path
                            tags
                        
                    
                
            
        
    `)))
    .then(( errors, data ) => 
        const  createPage  = boundActionCreators;
        const pageTemplate = path.resolve('./src/templates/page.js');

        if (errors) return Promise.reject(errors);

        return data.allMarkdownRemark.edges.forEach(edge => 
            createPage(
                path: edge.node.frontmatter.path,
                component: pageTemplate,
                context: 
                    path: edge.node.frontmatter.path,
                    tags: getUniqueTags(data.allMarkdownRemark.edges)
                
            );
        );
    )
    .catch(err => console.log(err));

那么您的templates/page.js 可以接收到这样的唯一标签数组:

const IndexPage = ( pathContext ) => 
    const  tags  = pathContext.map(tag => <li> tag </li>);

    return <div> tags </div>;
;

export default IndexPage;

【讨论】:

我发现自己实现了相同的方法。如果这种方法有任何危险,或者解释如何使用片段来实现相同的结果,我会很高兴从@KyleMathews 到这里。 如果不查看您的数据模型(或了解您的源插件),很难了解更多信息,但理想情况下,您可以通过每个页面组件中的 pageQuery 直接从 GraphQL 获取所有标签。这显示了一般方法github.com/gatsbyjs/gatsby/blob/master/docs/docs/…【参考方案2】:

您可以在 layouts/index.js 中创建片段查询

export const avatarsFragmentQuery = graphql`
  fragment avatars on RootQueryType 
    avatars: allImageSharp 
      edges 
        node 
           id

         
       
    
  
`

并在您的页面中使用它:

export const pageQuery = graphql`
  query BlogQuery 
    site 
      siteMetadata 
        title
      
    

    ...avatars
  
`

【讨论】:

以上是关于Gatsby 具有自己查询的可重用组件的主要内容,如果未能解决你的问题,请参考以下文章

具有 set Input() 任何类型的可重用组件是一个好习惯吗?

在 Angular 6 中使用具有输入属性的可重用组件

React 中的可重用组件

如何在 Blazor 的可重用表组件中显示数据

重用具有不同样式的 React 组件

Magnolia 中的可重用表单组件