Closed fsgreco closed 5 years ago
@yogeshkotadiya i think the easiest and cleanest solution here is to not embed the hero component in the layout and rather move it in the page templates / components. there you have the page specific context. just imagine you would have single-blog pages where you would have to check all the slugs manually and output the right hero image in the layout component. would be pretty messy haha. so i think best approach is here it to remove every non generic component which differs per page from the layout to the designated pages.
another option is you could leave the hero image in layout and pass the image data as a prop to Layout component on every page you need it. i hope this is clear if not feel free to ask.
both approaches have pros and cons. i you leave the hero in layout you can have no page specific changes to it in case you would need for example an extra title in it for some pages e. g. but as a pro you only need to embed the code once in layout. so if you dont need page specific changes in this component (except the different images) this approach would be ok.
@arturhenryy Hi, thanks for the suggestion. I removed the condition inside Spring, leaving only the Img component of the main-hero that already worked in the homepage. This to be sure that it wasn't that "Spring" component.
Then I created imghero.js component and placed it within a condition in the main layout like this:
import ImgHero from "./imgHero"
[...]
</Spring>
{location.pathname !== '/' && <ImgHero /> }
<MainLayout>
[...]
This is the content of ImgHero component:
import React from 'react'
import { graphql } from 'gatsby'
import Img from 'gatsby-image'
export const query = graphql`
query ImgHeroQuery($slug: String!) {
markdownRemark(frontmatter: {slug: {eq: $slug}}) {
frontmatter {
slug
hero {
id
childImageSharp {
fluid(maxWidth: 1900, quality: 100) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`
const ImgHero = ({ data, location }) => (
<div location={location}>
<Img
key={data.markdownRemark.frontmatter.hero.id}
fluid={data.markdownRemark.frontmatter.hero.childImageSharp.fluid}
/>
</div>
)
export default ImgHero;
It gives me some warnings during compiling (although it compiles well):
warning The GraphQL query in the non-page component "/home/santiago/..../src/components/imgHero.js" will not be run.
Exported queries are only executed for Page components. Instead of an exported
query, either co-locate a GraphQL fragment and compose that fragment into the
query (or other fragment) of the top-level page that renders this component, or
use a <StaticQuery> in this component. For more info on fragments and
composition, see http://graphql.org/learn/queries/#fragments and for more
information on <StaticQuery>, see https://gatsbyjs.org/docs/static-query
Homepage works as espected but now all the other posts results in a completely white screen on the browser, this are the errors of the console:
Uncaught TypeError: Cannot read property 'markdownRemark' of undefined
[...]
The above error occurred in the <ImgHero> component:
[...]
React will try to recreate this component tree from scratch using the error boundary you provided, LocationProvider.
The above error occurred in the <LocationProvider> component:
[...]
I think the problem is in the location, but I'm already passing that location property also in the ImgHero component...
another option is you could leave the hero image in layout and pass the image data as a prop to Layout component on every page you need it. i hope this is clear if not feel free to ask.
I'm a bit confused with this option you pointed out. I thought that props can only be passed from top to bottom. I mean it's possible to tell the main layout to take fluid={data.markdownRemark.frontmatter.hero.childImageSharp.fluid}
from the post component?
You are getting this error because in a non page component you need to use static query https://www.gatsbyjs.org/docs/static-query/
warning The GraphQL query in the non-page component
You are getting this error because in a non page component you need to use static query https://www.gatsbyjs.org/docs/static-query/
warning The GraphQL query in the non-page component
I convert the query on a StaticQuery. Now the image on the post is always the same. Its the hero image of my first post. It's like Gatsby don't filter the right hero image, it only take the one that appears first (I think this happens because I can't give a variable on a static query, in order to tell Gatsby to filter according to the slug).
This is my new ImgHero.js component:
import React from 'react'
import { graphql, StaticQuery } from 'gatsby'
import Img from 'gatsby-image'
const ImgHero = ({ location }) => (
<StaticQuery
query={graphql`
query ImgHeroQuery {
markdownRemark {
frontmatter {
slug
hero {
id
childImageSharp {
fluid(maxWidth: 1900, quality: 100) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`}
render={data => (
<div location={location}>
<Img
key={data.markdownRemark.frontmatter.hero.id}
fluid={data.markdownRemark.frontmatter.hero.childImageSharp.fluid}/>
</div>
)
}
/>
)
export default ImgHero;
Thats correct static query does not accept variables.
Thats correct static query does not accept variables.
That's my problem :/ Is there any way to tell gatsby to evaluate the context here? Even if this is not a page query?
Typically this would be accomplished as its shown in this tutorial. https://www.gatsbyjs.org/tutorial/part-seven/#creating-pages
You would have a template file such as:
component: path.resolve(./src/templates/blog-post.js
),
And this file would contain your query.
Typically this would be accomplished as its shown in this tutorial. https://www.gatsbyjs.org/tutorial/part-seven/#creating-pages
You would have a template file such as: component: path.resolve(
./src/templates/blog-post.js
),And this file would contain your query.
I already do that, indeed I have a postLayout.js where there is a Page Query that is used to create the posts. But I can't replicate that query on my imghero.js because it's not a page. So I'm stucked.
Now I followed the warming that Gatsby gives me when was compiled that second page query. So I put a fragment on my postLayout.js:
import React from 'react'
import { graphql } from 'gatsby'
import Transition from "../components/transition"
import styled from 'styled-components'
export const query = graphql`
query PostQuery($slug: String!) {
markdownRemark(frontmatter: {
slug: {
eq: $slug
}
}) {
html
frontmatter {
...imghero
}
}
}
fragment imghero on frontmatter_2 {
slug
date
title
hero {
id
childImageSharp {
fluid {
src
...GatsbyImageSharpFluid_tracedSVG
}
}
}
}
`
const PostWrapper = styled.div`
max-width: 42rem;
margin: 0 auto;
`
const postLayout = ({ data, location }) => (
// <Layout location={location}>
<Transition location={location}>
<PostWrapper>
<h1>Questo è: { data.markdownRemark.frontmatter.title} </h1>
<div dangerouslySetInnerHTML={{
__html: data.markdownRemark.html
}}/>
</PostWrapper>
</Transition>
//</Layout>
)
export default postLayout;
And this is my imgHero.js component:
import React from 'react'
import { graphql, StaticQuery } from 'gatsby'
import Img from 'gatsby-image'
const ImgHero = ({ location }) => (
<StaticQuery
query={graphql`
query ImgHeroQuery {
markdownRemark {
frontmatter {
slug
...imghero
}
}
}
`}
render={data => (
<div location={location}>
<Img
key={data.markdownRemark.frontmatter.hero.id}
fluid={data.markdownRemark.frontmatter.hero.childImageSharp.fluid}/>
</div>
)
}
/>
)
export default ImgHero;
It gives me no errors at all, but the posts have all the same image :( I have run out of ideas here
@anonimoconiglio as i said before, please move the ImgHero component inside your postLayout and pass the image data as a prop. you can also remove the key from the Img inside ImgHero because you dont iterate
I think you want something like this:
import React from 'react'
import { graphql } from 'gatsby'
import Transition from "../components/transition"
import styled from 'styled-components'
import Img from 'gatsby-image'
export const query = graphql`
query($slug: String!) {
markdownRemark(frontmatter: {slug: {eq: $slug}}) {
frontmatter {
title
hero {
id
childImageSharp {
fluid(maxWidth: 1900, quality: 100) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`
const PostWrapper = styled.div`
max-width: 42rem;
margin: 0 auto;
`
const postLayout = ({ data, location }) => (
// <Layout location={location}>
<Img
fluid={data.markdownRemark.frontmatter.hero.childImageSharp.fluid}
/>
<Transition location={location}>
<PostWrapper>
<h1>Questo è: { data.markdownRemark.frontmatter.title} </h1>
<div dangerouslySetInnerHTML={{
__html: data.markdownRemark.html
}}/>
</PostWrapper>
</Transition>
//</Layout>
)
export default postLayout;
@arturhenryy @t2ca I already tried but unfortunately that's not a solution, since I want that the image takes the place of the main-hero, with this solution the image resides on it's relative post but there is a sidebar and a hero that still remain in their place.
Here's an example of what I mean. This is the homepage:
And this is the result if I put the Img component inside postLayout.js:
I think you can do something like
const postLayout = ({ data, location }) => (
<Layout hero={data.markdownRemark.frontmatter.hero.childImageSharp.fluid}>
<Transition location={location}>
<PostWrapper>
<h1>Questo è: { data.markdownRemark.frontmatter.title} </h1>
<div dangerouslySetInnerHTML={{
__html: data.markdownRemark.html
}}/>
</PostWrapper>
</Transition>
</Layout>
)
export default postLayout;
Inside your Layout component you will have a hero prop
const Layout = props => (
[...]
{location.pathname === '/'
? (<Img fluid={data.file.childImageSharp.fluid} />)
: <Img fluid={props.hero} /> ))
)
}
[...]
@t2ca Thanks, I tried with a div instead of "Layout" (I don't use Layout because I'm using gatsby-plugin-layout to make the layout "static" or "fixed". So it automatically wraps my postLayout component (its children))
const postLayout = ({ data, location }) => (
<div hero={data.markdownRemark.frontmatter.hero.childImageSharp.fluid}>
<Transition location={location} >
<PostWrapper >
<h1>Questo è: { data.markdownRemark.frontmatter.title} </h1>
<div dangerouslySetInnerHTML={{
__html: data.markdownRemark.html
}}/>
</PostWrapper>
</Transition>
</div>
)
and then this (to simplify things for the moment):
const Layout = ({ children, location, props }) => (
<StaticQuery
query={QUERY_MAIN_LAYOUT}
render={data => (
<>
[...]
{location.pathname !== '/' && <Img fluid={props.hero} /> }
Compilation goes fine but post pages are white again, with this errors:
Uncaught TypeError: Cannot read property 'hero' of undefined
[...]
The above error occurred in the <Context.Consumer> component:
[...]
The above error occurred in the <LocationProvider> component:
[...]
Sorry i'm not familiar with using gatsby-plugin-layout
Sorry i'm not familiar with using gatsby-plugin-layout
do you think that's generating the problem? I thought it only wrapped the layout in its children.
Well this code below is incorrect which is causing the undefined error.
const Layout = ({ children, location, props }) => (
<StaticQuery
query={QUERY_MAIN_LAYOUT}
render={data => (
<>
[...]
{location.pathname !== '/' && <Img fluid={props.hero} /> }
It would be something like
const Layout = ({ children, location, hero }) => (
<StaticQuery
query={QUERY_MAIN_LAYOUT}
render={data => (
<>
[...]
{location.pathname !== '/' && <Img fluid={hero} /> }
@t2ca mm ok, now there is only one error (always in the browser, it compiles well):
Uncaught TypeError: Cannot read property 'src' of undefined
[...]
The above error occurred in the <Image> component:
[...]
The above error occurred in the <LocationProvider> component:
Im sorry, i'm not sure, i don't any experience with gatsby-plugin-layout
Im sorry, i'm not sure, i don't any experience with gatsby-plugin-layout
It's ok, thanks for your help anyway :)
I created a demo on github if you want to take a look (now all the config resides on springhero.js component): https://github.com/anonimoconiglio/gatsby-for-debugging
Thanks for the help. cc/ @t2ca
Hiya!
This issue has gone quiet. Spooky quiet. 👻
We get a lot of issues, so we currently close issues after 30 days of inactivity. It’s been at least 20 days since the last update here.
If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not stale" to keep this issue open!
Thanks for being a part of the Gatsby community! 💪💜
Hey again!
It’s been 30 days since anything happened on this issue, so our friendly neighborhood robot (that’s me!) is going to close it.
Please keep in mind that I’m only a robot, so if I’ve closed this issue in error, I’m HUMAN_EMOTION_SORRY
. Please feel free to reopen this issue or create a new one if you need anything else.
Thanks again for being part of the Gatsby community!
EDIT:
I created a demo on github if you want to take a look (now all the config resides on springhero.js component): https://github.com/anonimoconiglio/gatsby-for-debugging
Summary
Sorry if this question seems noob, I tried everything and feel like there's something missing but I don't understand how to do it.
I need to change my hero-image (that is part of the main layout) according to the page (its slug). Every post has a hero-image, setted in the frontmatter info. So I need to tell Gatsby to use the image of the post that has loaded, instead of the main hero-image.
I used a conditional statement that works well to distinguish the homepage that anything else, then iterate
allMarkdownRemark
and set the alternative image with a key prop. Now, as far as I have understand using a "key" prop isn't enought because it shows me all the images of the posts instead of filter the right one according to the slug.It seems that I need to allow Gatsby to undestand the context of the page (like with my singlePagePost component), so it can filter the right image according to the page loaded.
But I can't use a
Page Query
with variables on the main layout, because it's not a page, so I run out of ideas...Relevant information
I'm using gatsby-plugin-layout in order to make the layout "static" (otherwise my Spring effect on hero image flickered, because it loaded the layout everytime).
My Changes
This is the last attempt on my main layout component, this is the conditional statement:
Here is the full Layout Component:
Environment (if relevant)
File contents (if changed)
Other files:
gatsby-config.js
:package.json
: N/Agatsby-node.js
:gatsby-browser.js
: N/Agatsby-ssr.js
: N/A