Thank you for taking the time to look at my problem. I would really appreciate any help.
**Update: Ok, so I think I know what's causing the problem but I don't know why. Before, on my products/merch page I only had one item in my database. On the products/beans page I had multiple items. On the products/merch page where there was only one result from the query the footer did not display twice. As soon as I added another item into the merch category and products/merch had two products, on page reload it also began to duplicate the footer.
Why would multiple queries have any effect on how a page renders? What could be some solutions to this? I'm going to try and pass the data in as props from the graphql to a allProducts component to see if that fixes the issue. **
I'm using Gatsby.js and Strapi headless CMS for an ecommerce site I'm building. On a page which displays all the products in a specific category, if the page is reloaded, it renders the footer twice. This is confusing because when the page first renders it's fine but only on reload does it do it. If the website loads from that specific page, it also displays two footers. Once I navigate to another page and reload, the second footer goes away. This page giving me an issue has a GraphQL query. I have another page that also has a GraphQL query but it does not to do this. Something in this page is causing in issue in rendering.
What I've tried: In gatsby-node.js, in the createPages export I had tried to create each page and pass a template and the context of "type" so that the GraphQL query could then filter for the data that the page needs. I thought that using createPage this way could cause a rendering issue. I've also tried removing the contents of the Footer component and directly placing them in layout.js. I've tried removing Layout component from the page and adding Header.js and Footer.js directly, still the same problem. I'm only experiencing this problem once i host it, not on the localhost. Is it an issue with Server Side Rendering? Here is a link to the site hosted on gatsby cloud, and if you click on any other page and refresh the second footer goes away but if you click back to this page and then refresh the second footer pops up again.
https://build-856af2e5-f049-46de-b6a5-9e11aa46a906.gtsb.io/products/beans/
createPage({
path: "/products/merch",
component: path.resolve(`src/templates/allproducts.js`),
context: {
type: "merch",
},
})
createPage({
path: "/products/beans",
component: path.resolve(`src/templates/allproducts.js`),
context: {
type: "beans",
},
})
So I then moved each page into a folder in the Gatsby pages folder. So Instead of using createPages to programmatically create them I made them traditionally by creating a products folder then adding a new page for each category. This did not resolve my issue by creating the pages manually instead of using createPages.
It doesn't make sense to me why the footer would load twice and not the header or the main component in my layout.js, which looks like this:
import React from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"
import Footer from "./Footer"
import Header from "./header"
import "./layout.css"
const Layout = ({ children }) => {
const data = useStaticQuery(graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`)
return (
<>
<Header siteTitle={data.site.siteMetadata.title} />
<main>{children}</main>
<Footer />
</>
)
}
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default Layout
Here is the Footer.js component:
import React from "react"
import { Facebook, Instagram, Twitter } from "@material-ui/icons"
import styled from "styled-components"
const BottomNav = styled.footer`
border-top: 1px solid black;
position: sticky;
height: 15vh;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
font-family: Raleway;
text-transform: uppercase;
`
const BottomNavContainer = styled.div`
display: flex;
justify-content: space-between;
width: 200px;
margin-bottom: 0.3rem;
`
const Footer = () => {
return (
<BottomNav>
<BottomNavContainer>
<Facebook />
<Instagram />
<Twitter />
</BottomNavContainer>
<div>
© {new Date().getFullYear()},{` `} The Blank
</div>
</BottomNav>
)
}
export default Footer
And here is the code for the pages that are duplicating the footer:
function Alert(props) {
return <MuiAlert elevation={6} variant="filled" {...props} />
}
const AllBeansPage = props => {
const products = props.data.allStrapiProduct.nodes
// const classes = useStyles()
const [open, setOpen] = React.useState(false)
const { addToCart } = useContext(CartContext)
const handleClick = () => {
setOpen(true)
}
const handleClose = (event, reason) => {
if (reason === "clickaway") {
return
}
setOpen(false)
}
return (
<Layout>
<SEO
title={
products[0].type.charAt(0).toUpperCase() + products[0].type.slice(1)
}
/>
<Fade in={true} timeout={{ enter: 2000, exit: 500 }}>
<AllProductsContainer>
<Container>
{products.map(product => (
<Slide
direction="left"
in={true}
mountOnEnter
unmountOnExit
timeout={{ enter: 1500, exit: 500 }}
>
<ProductCard key={product.id}>
<Link
key={product.id}
style={{}}
to={`products/${product.type}/${product.slug}`}
>
<ImageContainer>
{console.log(product.thumbnail.childImageSharp.fluid)}
<Img
key={product.id}
fluid={product.thumbnail.childImageSharp.fluid}
/>
</ImageContainer>
</Link>
<ProductContent>
<Typography
gutterBottom
variant="h5"
component="h1"
style={{
fontFamily: "Caveat",
fontSize: "clamp(22px, 3vw, 28px)",
}}
>
{product.name}
</Typography>
<Typography
variant="body2"
color="textSecondary"
style={{ fontSize: "clamp(12px, 1.5vw, 16px)" }}
>
{product.description.slice(0, 35)}...
</Typography>
<Link
key={product.id}
style={{}}
to={`products/${product.type}/${product.slug}`}
>
{" "}
<Typography
variant="subtitle1"
color="primary"
style={{ fontSize: "clamp(14px, 1.5w, 18px)" }}
>
Learn More
</Typography>
</Link>
</ProductContent>
<CardActionArea>
<CardActions
style={{
display: "flex",
justifyContent: "space-between",
}}
>
<Button
size="small"
color="primary"
onClick={() => {
addToCart(product, 1)
handleClick()
}}
style={{ fontSize: "clamp(12px, 1.5vw, 18px)" }}
>
Add To Cart
</Button>
<Typography
variant="body1"
style={{ fontSize: "clamp(12px, 1.5vw, 18px)" }}
>
{formatPrice(product.price_in_cents)}
</Typography>
</CardActions>
</CardActionArea>
</ProductCard>
</Slide>
))}
</Container>
</AllProductsContainer>
</Fade>
<Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>
<Alert onClose={handleClose} severity="success">
Item successfully added to cart.
</Alert>
</Snackbar>
</Layout>
)
}
export default AllBeansPage
export const productQuery = graphql`
query allBeanQuery {
allStrapiProduct(filter: { type: { eq: "beans" } }) {
nodes {
strapiId
id
description
created_at
price_in_cents
name
slug
type
thumbnail {
childImageSharp {
fluid(quality: 100, maxWidth: 150, maxHeight: 150) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`