Gatsby: [Question] What's different when passing data via props.pathContext and props.data?

Created on 7 Nov 2017  Â·  16Comments  Â·  Source: gatsbyjs/gatsby

In the Tutorial, I learned that I can pass data via context when calling createPage and it will be the GraphQL variables.
My question is why not just passing the queried data directly and using props.pathContext in the JSX? This will avoid an external query. What's different when using context as the GraphQL variables and the component props?

question or discussion

Most helpful comment

The end result is the same yes as you've figured out.

We encourage writing GraphQL queries directly in page components because then components are more self-documenting. When working on a component, if your graphql query is there, it's easy to understand what data is accessible + make changes/additions as needed.

Another advantage of queries in components is these "hot reload" (i.e. get re-run) when you change them where data passed in from gatsby-node.js doesn't get refreshed unless you restart the "gatsby develop" process.

So in short, there's significant advantages to putting queries in your components and it's highly recommended over passing in data when creating pages.

All 16 comments

The end result is the same yes as you've figured out.

We encourage writing GraphQL queries directly in page components because then components are more self-documenting. When working on a component, if your graphql query is there, it's easy to understand what data is accessible + make changes/additions as needed.

Another advantage of queries in components is these "hot reload" (i.e. get re-run) when you change them where data passed in from gatsby-node.js doesn't get refreshed unless you restart the "gatsby develop" process.

So in short, there's significant advantages to putting queries in your components and it's highly recommended over passing in data when creating pages.

Thank you very much for quick response and detailed explanation. :)
But there is also an advantage of using context. We can take full control of the data, for example we can use filter to create a tag archive page for blog. Also we can still document out component using the built-in prop-type.
My advice is why not mentioning both two ways in the document and letting the user to choose?

@PoiScript you can filter in queries too :-) As well as sort, etc. e.g. https://github.com/gatsbyjs/gatsby/blob/0675e275d57bf857fbcf1214849affea40a87b63/examples/using-remark/src/templates/template-tag-page.js#L34

Our opinion is that colocated declarative data querying is far superior than putting all that in gatsby-node.js. Imagine a large site with dozens of page templates — all the data logic would be crammed together and get quite complicated. Far better to have that logic in simple declarative queries in the actual components.

@KyleAMathews For the use case in which a query needs the result from a previous query. Can both the queries be colocated in the same component? Currently the way I do it is, running the first query in gatsby-node.js and passing the result to a template component.

@KyleAMathews do you have any comments on the relative performance of the two methods? On the face of it, passing data through from gatsy-node.js via context seems like it ought to be faster than colocated method, if there are many pages in the site, because it will drastically reduce the number of graphql queries required. In the case where there is a large set of pages, but relatively few templates (e.g. two) how do you feel about using the gatsby-node method?

Running queries are extremely quick and a very small part of the build time. Also we don't run GraphQL queries on subsequent builds if the data for that page hasn't changed.

A better question is which is best for developer ergonomics & long-term maintainability. If all the data necessary for a page component is defined in its query, then it's easy to know what data is available and in what shape. It's also easy to add and remove fields from the query as you modify the component. Also the query gets automatically re-run when it's in the page component but not the createPages query.

The context object for creating pages was only intended for passing arguments to the page component query and it didn't occur to me that people would pass more data directly for use in the page not to mention their entire page payload.

Curious how you picked up this technique? Is there a popular tutorial somewhere that teaches this method?

@KyleAMathews, just happened to read this article from Auth0 tonight. It suggests doing this on the homepage which is technically a template in this case.

They're passing in "pagination" data which is expected. The distinction is that you only pass in data via context that's required to uniquely identify the page you're creating. So what "page" the page is in the pagination is essential so that each page can query the right slice of data.

@KyleAMathews thank you very much. As newcomers to Gatsby, @ric9176 and I were trying to work out the best way to render a site with over 5000 pages; the gatsby-node method that you don't advise seemed natural to me for reasons of performance; we didn't find it in a tutorial.

maybe there could be process intensive tasks which could be better to do once in gatsby-node instead of the actual page?!

@KyleAMathews, On a related note, I'm curious why in the examples of gatsby-node.js the implementation when programmatically building pages uses forEach rather than using map. Is this due to a potential memory allocation issue? As we are dealing with a very large data set (now over 10,000 pages) we went for map as it's more performant, but I'm curious about your thoughts on this. As the amount of programmatically generated pages is so large, reducing the build time is something we are looking into as we refactor as it's now up to around 20 minutes. Thanks in advance :smile:

Because forEach is semantically correct even if you can accomplish the same thing with map. Also map isn't necessarily always going to be faster.

@KyleAMathews RE: Auth0 article, they are passing in all of the data for the page. group is an array posts with frontmatter and the excerpt.

The main difference between the original src/pages/index.js and our src/templates/index.js is that we don't need a graphql query to retrieve the articles for the page. Instead, we're using the result of the data in our gatsby-node.js file to render to pages we need.

The template used they used does not have any query at all on it. I was under the impression that The Right Way was to pass index/increment type data that a query on the template can use in filtering, via skip/limit.

I have seen this pattern in the article show up a few times now. Especially since this is the homepage, my assumption was that that pattern is just extrapolated to the rest of their website. @shannonbux, have you seen this happen at all?

@jbolda can you clarify your question? What is the word "this" referring to? Happy to help. It does seem that there is potentially something we can clarify in the docs based on this discussion.

No problem @shannonbux. "This" refers to the template that creates the homepage. With a pagination example, typically the tutorial comprises a homepage that displays all posts paginated, and a page/template to display each post itself. So if the example shows passing all of the data through context for the homepage, my assumption was that someone might assume that it is the best method for the rest of the website.

I think ultimately, I am just looking for clarification on the use of context, the option located in the createPage. I can't find anything in the docs that directly explains the use of context as discussed in this thread. My understanding is that the original intention was to pass variables that the template could use. This leads me to believe that pagination would look something like the quote from this thread, #2616 :

You can use context values as GraphQL query arguments.

I've done it like this. The context, for createPage, contains:

context: {
 skip: i,
 limit: articlesPerPage,
 total: total
}

And the GraphQL query inside the template:

query Query($skip: Int!, $limit: Int!) {
 allMarkdownRemark(skip: $skip, limit: $limit, ...) {
   ...

However, most examples including the gatsby-paginate plugin pass all of the data over context as shown below. Note: group contains each post item's frontmatter, excerpt, etc. And then our homepage template has no query at all.

        context: {
          group: group,
          nextPath: pageToPath(pageNumber - 1, pathPrefix, maxPages),
          prevPath: pageToPath(pageNumber + 1, pathPrefix, maxPages),
          extraContext: context
        }

It seems that there are no performance benefits either way that this is achieved. As such, only using context for variables and storing queries on templates is suggested primarily for organizational purposes. I believe it would be beneficial to state this in the docs. But if we are promoting context only for variables to use in a query, I cannot personally answer the question "why?" we seem to be promoting the use of codeblock above rather than the quoteblock further up. I suspect that it is just that pagination gets complex quickly and the value of storing the query on the template is lost in that complexity.

The specific reason that I tagged you, @shannonbux, was that I was hoping you may be able to provide some insight how context is generally used, if there is confusion around it for a majority of users or not, and if these pagination examples have any effect on it.

thanks @jbolda and others! I have heard similar feedback although I'm not exactly sure how to address it since I am not a developer (yet) :). One thing I can say is that perhaps you could check out my RFC for reorganizing the docs and comment if you can think of the most logical place in the docs to explain the advantages of using GraphQL queries vs. other options.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

3CordGuy picture 3CordGuy  Â·  3Comments

ghost picture ghost  Â·  3Comments

ferMartz picture ferMartz  Â·  3Comments

signalwerk picture signalwerk  Â·  3Comments

theduke picture theduke  Â·  3Comments