【问题标题】:How to reduce static query code duplication Gatsby JS如何减少静态查询代码重复 Gatsby JS
【发布时间】:2020-12-25 19:13:14
【问题描述】:

我创建了一个请求站点和页面级元数据的 React 静态查询挂钩。目前,我在每个页面构建中都复制此代码,因为查询的一部分从页面到页面allProductsJsonallProductJson 等发生变化。我想知道是否可以通过使用查询功能来删除这种重复更有效率?我读过 Gatsby 静态查询不支持参数,但也许有一种方法可以查询所有元数据并按页面过滤?

重复查询挂钩示例:

import { graphql, useStaticQuery } from 'gatsby';
import pageMetadataSelector from 'utils/page-metadata-selector';
import siteMetadataSelector from 'utils/site-metadata-selector';
import getAbsoluteUrl from 'utils/get-absolute-url-path';

const QUERY = graphql`
  {
    pageMetadata: allProductsJson {
      nodes {
        metadata {
          title
          description
          image {
            publicURL
          }
          robots
        }
      }
    }
    site {
      siteMetadata {
        siteUrl
      }
    }
  }
`;

const usePageMetadataQuery = ({ location }) => {
  const { pageMetadata, site } = useStaticQuery(QUERY);
  const pageData = pageMetadataSelector(pageMetadata);
  const { siteUrl } = siteMetadataSelector(site);

  return {
    metadata: {
      ...pageData,
      siteUrl: getAbsoluteUrl(siteUrl, location.pathname),
      image: getAbsoluteUrl(siteUrl, pageData.image.publicURL)
    }
  };
};

export default usePageMetadataQuery;

【问题讨论】:

标签: reactjs graphql gatsby


【解决方案1】:

鉴于您在这里所做的事情,我认为通过将相关数据添加到页面上下文中gatsby-node.js(在createPage 调用中),然后使用wrapRootElement(在gatsby-browser.jsgatsby-ssr.js) 从页面上下文中提取这些详细信息。

您可以从那里直接渲染您需要的组件,也可以将其传递给 React Context Provider 以供任何子级使用。

这是一个显示后者的示例:

export const wrapPageElement = ({ element, props: { context: { metadata} } }) => {
  return (
    <MetadataContext.Provider value={metadata}>
      {element}
    </MetadataContext.Provider>
  )
}

也可以在您的每个页面查询中获取这些数据并以相同的方式访问它(解构 data 而不是 context):

exports.createPages = async ({ graphql, actions }) => {
  const {
    data: {
      pageMetadata,
      pageData,
    }
  } = await graphql(`
    {
      pageMetadata: allProductsJson {
        nodes {
          slug
          metadata {
            title
            description
            image {
              publicURL
            }
            robots
          }
        }
      }

      pageData: allPageJson {
        pages: {
          slug
        }
      }
    }
  `

  // for each page
  pageData.pages.map(({ slug }) => {
    // select the metadata with the matching slug
    const { metadata } = pageMetadata.nodes.find(node => node.slug === slug)
    
    // create the page
    actions.createPage({
      path: `/${slug}/`,
      component: `./src/templates/page.jsx`,
      context: { 
        // pass both the slug and metadata as context
        slug,
        metadata,
      }
    })
  })
}

【讨论】:

  • 问题是关于使用略有不同的查询总是别名为pageMetadata 并以相同的方式处理
  • @coreyward 元数据会随着页面的变化而变化,所以我可以查询allProductsJsonallProductJson 等,想知道如何获得这种灵活性?
  • 对。而不是从页面查询中的allProductJson 或静态查询中提取您需要的数据,您只需在gatsby-node.js 中执行它并将其相关切片作为上下文传递给createPage 调用。
  • 否则您可以使用为每个页面运行的页面查询来获取此数据。此外,您仍然可以从传递给wrapPageElementprops 属性中获取location,就像我在上面的示例中对context 所做的那样对其进行解构。
  • @coreyward 很抱歉很晚才回来,我仍然不确定的部分是如果我将查询添加到 gatsby-node 我如何采摘allProductJson 然后可能是allStoresJson并将该切片作为上下文返回?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多