Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Impossible to declare multiple components that use <StaticQuery> in one file #9580

Closed
ukch opened this issue Oct 30, 2018 · 12 comments
Closed
Labels
stale? Issue that may be closed soon due to the original author not responding any more. type: bug An issue or pull request relating to a bug in Gatsby

Comments

@ukch
Copy link

ukch commented Oct 30, 2018

Description

Say I want to have multiple components in a single file, that both use StaticQuery in one form or another.

Example code:

// src/components/things.js

import React from "react";
import {StaticQuery} from "gatsby";

export const MyFirstQuery = (props) => (
    <StaticQuery query={some_query} render={() => <div>hello world</div>} />
);

export const MySecondQuery = (props) => (
    <StaticQuery query={some_query} render={() => <div>hello world</div>} />
);
// src/pages/testpage.js

import React from "react";
import { MyFirstQuery } from "../components/things";

export const () => (
    <div>
        Here is my first static query:
        <MyFirstQuery />
    </div>
);

The page will render as expected when using gatsby develop, but gatsby build will cause the following error to occur:

error Generating JavaScript bundles failed

  Error: ./src/components/things.js 6:7
  Module parse failed: Identifier 'staticQueryData' has already been declared (6:7)
  You may need an appropriate loader to handle this file type.
  | import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose";
  | import staticQueryData from "../../public/static/d/2162154064.json";
  > import staticQueryData from "../../public/static/d/2162154064.json";
  | import { StaticQuery } from "gatsby";
   @ ./src/pages/testpage.js 2:0-47 105:31-39
   @ ./.cache/async-requires.js
   @ ./.cache/production-app.js

Steps to reproduce

  • Create a simple starter site.
  • Copy the two files above (replace some_query with any valid GraphQL query)
  • gatsby build

Expected result

The project should build. It shouldn't matter that the two StaticQuerys are in the same file.

Actual result

See the error above.

Environment

I am unable to post info due to #8502. However, I am running gatsby-cli version 2.4.4 (globally installed), and gatsby version 2.0.35.

@oorestisime oorestisime added type: bug An issue or pull request relating to a bug in Gatsby status: inkteam to review labels Oct 30, 2018
@LekoArts
Copy link
Contributor

I made a reproduction repo where this behavior can be observed: https://github.com/LekoArts/two-static-repro

@mik-laj
Copy link

mik-laj commented Jan 2, 2019

I recommend using HOC to reduce the code repetition.

// src/components/things.js

import React from "react";
import { StaticQuery } from "gatsby";

const withData = (WrappedComponent) = (
  (props) => 
    <StaticQuery query={some_query} render={(data) => 
      <WrappedComponent {...props} data={data}/>
    } />  
)

export const MyFirstQuery = withData(({data, ...props}) => (
    <div>hello world</div>
));

export const MySecondQuery = withData(({data, ...props}) => (
    <div>hello world</div>
));

But the error still in Gatsby will exist. My answer should be treated as a solution for others with this problem, until this problem is solved.

@jonniebigodes
Copy link

@mik-laj Thanks for the quick fix. It will probably be helpfull for people experiencing this issue. 👍

@Coder2012
Copy link

Coder2012 commented Jan 28, 2019

@mik-laj

Thank you for your solution, I don't quite understand how to use it with multiple queries though. How does some_query get passed in to the StaticQuery?

Would you be able to show example please?

@jtran19
Copy link

jtran19 commented Feb 10, 2019

@Coder2012 Maybe a more fleshed out example might help. I was having this issue as well and @mik-laj comment flipped on the lightbulb for me.

// src/components/image.js

function withImageData(WrappedComponent) {
  return props => (
    <StaticQuery
      query={graphql`
        query AstronautImageQuery {
          placeholderImage: file(relativePath: { eq: "gatsby-astronaut.png" }) {
            childImageSharp {
              fluid(maxWidth: 300) {
                ...GatsbyImageSharpFluid
              }
            }
          }
          logoImage: file(relativePath: { eq: "logo.png" }) {
            childImageSharp {
              resolutions {
                width
                height
                src
                srcSet
              }
            }
          }
        }
      `}
      render={data => <WrappedComponent {...props} imageData={data} />}
    />
  );
}

const Image = withImageData(props => (
  <Img fluid={props.imageData.placeholderImage.childImageSharp.fluid} />
));
const Logo = withImageData(props => (
  <Img resolutions={props.imageData.logoImage.childImageSharp.resolutions} />
));

export { Image, Logo };

With this, I can now do...

// src/testlogo.js

import { Logo } from './components/image';
export default () => <Logo />

By using GraphQL aliases, you can query for as many image files as you need to, and your wrapped components just pluck out the one(s) they need.

@anicolaides
Copy link

anicolaides commented Feb 15, 2019

Although this is not a solution to the issue, as of Gatsby v2.1.0, useStaticQuery can be used.

Instead of using this design pattern:

import {StaticQuery, graphql } from 'gatsby'

const ImagesQ = graphql`
  fragment servicesImage on File {
    childImageSharp {
      fluid(maxWidth: 500) {
        ...GatsbyImageSharpFluid_withWebp
      }
    }
  }

  query {
    image1: file(relativePath: { eq: "entrance.jpg" }) {
      ...servicesImage
    }

    image2: file(relativePath: { eq: "students.jpg" }) {
      ...servicesImage
    }

    image3: file(relativePath: { eq: "flags.jpg" }) {
      ...servicesImage
    }

    image4: file(relativePath: { eq: "admission.jpg" }) {
      ...servicesImage
    }

    image5: file(relativePath: { eq: "support.jpg" }) {
      ...servicesImage
    }
  }
`

// Along with... multiple StaticQuery elements
const MyComponent = () => (
  <div>
    <StaticQuery
      query={ImagesQ}
      render={data => <Img fluid={data.image#.childImageSharp.fluid} />}
    />
   // blah...
</div>
)

One may use the following:

const Services = () => {
  const data = useStaticQuery(graphql`
    fragment servicesImage on File {
      childImageSharp {
        fluid(maxWidth: 500) {
          ...GatsbyImageSharpFluid_withWebp
        }
      }
    }

    query {
      image1: file(relativePath: { eq: "entrance.jpg" }) {
        ...servicesImage
      }

      image2: file(relativePath: { eq: "students.jpg" }) {
        ...servicesImage
      }

      image3: file(relativePath: { eq: "flags.jpg" }) {
        ...servicesImage
      }

      image4: file(relativePath: { eq: "admission.jpg" }) {
        ...servicesImage
      }

      image5: file(relativePath: { eq: "support.jpg" }) {
        ...servicesImage
      }
    }
  `)

  return (
    <Img fluid={data.image1.childImageSharp.fluid} />
  )}

Much cleaner as well :).

@Alfrex92
Copy link

Alfrex92 commented Mar 2, 2019

thanks @anicolaides it is working :D

@gatsbot gatsbot bot added the stale? Issue that may be closed soon due to the original author not responding any more. label Mar 23, 2019
@gatsbot
Copy link

gatsbot bot commented Mar 23, 2019

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! 💪💜

@gatsbot
Copy link

gatsbot bot commented Apr 3, 2019

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!

@gatsbot gatsbot bot closed this as completed Apr 3, 2019
@bantek89
Copy link

bantek89 commented Jun 3, 2019

Although this is not a solution to the issue, as of Gatsby v2.1.0, useStaticQuery can be used.

Instead of using this design pattern:

import {StaticQuery, graphql } from 'gatsby'

const ImagesQ = graphql`
  fragment servicesImage on File {
    childImageSharp {
      fluid(maxWidth: 500) {
        ...GatsbyImageSharpFluid_withWebp
      }
    }
  }

  query {
    image1: file(relativePath: { eq: "entrance.jpg" }) {
      ...servicesImage
    }

    image2: file(relativePath: { eq: "students.jpg" }) {
      ...servicesImage
    }

    image3: file(relativePath: { eq: "flags.jpg" }) {
      ...servicesImage
    }

    image4: file(relativePath: { eq: "admission.jpg" }) {
      ...servicesImage
    }

    image5: file(relativePath: { eq: "support.jpg" }) {
      ...servicesImage
    }
  }
`

// Along with... multiple StaticQuery elements
const MyComponent = () => (
  <div>
    <StaticQuery
      query={ImagesQ}
      render={data => <Img fluid={data.image#.childImageSharp.fluid} />}
    />
   // blah...
</div>
)

One may use the following:

const Services = () => {
  const data = useStaticQuery(graphql`
    fragment servicesImage on File {
      childImageSharp {
        fluid(maxWidth: 500) {
          ...GatsbyImageSharpFluid_withWebp
        }
      }
    }

    query {
      image1: file(relativePath: { eq: "entrance.jpg" }) {
        ...servicesImage
      }

      image2: file(relativePath: { eq: "students.jpg" }) {
        ...servicesImage
      }

      image3: file(relativePath: { eq: "flags.jpg" }) {
        ...servicesImage
      }

      image4: file(relativePath: { eq: "admission.jpg" }) {
        ...servicesImage
      }

      image5: file(relativePath: { eq: "support.jpg" }) {
        ...servicesImage
      }
    }
  `)

  return (
    <Img fluid={data.image1.childImageSharp.fluid} />
  )}

Much cleaner as well :).

@anicolaides I'm a bit stuck with this, could you please expand on how you would access image2, image 3 etc with the 'useStaticQuery' method? I can only manage to return one Img component with the first query for image1.

Thanks!

@TheFirstMe
Copy link
Contributor

TheFirstMe commented Jul 28, 2019

@bantek89 You can pass an imageName prop to Services and use data[imageName].childImageSharp.fluid. Then <Services imageName="image#" /> gives you the image

@maghin0
Copy link

maghin0 commented Feb 18, 2020

guys, I love this, it saved my life, but one more thing I am a Graphql newbie and don't know how to use folders instead of a file on fragments (assuming I can have multiple fragments on one staticquery
@TheFirstMe @bantek89

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale? Issue that may be closed soon due to the original author not responding any more. type: bug An issue or pull request relating to a bug in Gatsby
Projects
None yet
Development

No branches or pull requests