How to use gatsby background image plugin - reactjs

I'm new to gatsby and i'm trying to use gatsby background image plugin but it does not work, the image wont show on screen.
Here's my code :
import * as React from "react"
import { graphql, useStaticQuery } from 'gatsby'
import { createGlobalStyle } from "styled-components"
import BackgroundImage from 'gatsby-background-image'
const GlobalStyle = createGlobalStyle`
body{
background-color: #270A63;
margin : 0px;
display:flex;
}`
const Layout = (props, { children }) => {
const data = useStaticQuery(
graphql`
query {
bgImage : file(relativePath: {eq: "background.png"}) {
childImageSharp {
gatsbyImageData(quality: 90)
}
}
}
`
)
const imageData = data.bgImage.childImageSharp.gatsbyImageData;
return (
<React.Fragment>
<GlobalStyle />
<BackgroundImage
Tag="section"
image={imageData}
>
</BackgroundImage>
</React.Fragment>
)
}
export default Layout
Layout is a custom component that I'm using in index page.
I used console.log to check imageData and it is an object that looks like this :
{bgImage:
childImageSharp:
gatsbyImageData:
backgroundColor: "#680818"
height: 1117
images:
fallback: {src: '/static/32d467ee3060062ab794e34f2002c807/f89cf/background.png', srcSet: '/static/32d467ee3060062ab794e34f2002c807/5829e/bac…60062ab794e34f2002c807/f89cf/background.png 1010w', sizes: '(min-width: 1010px) 1010px, 100vw'}
sources: [{…}]
[[Prototype]]: Object
layout: "constrained"
width: 1010}
I don't understand why it does not work.
Thank you for your help !

As per your GraphQL, you are using a Gatsby version greater or equal than 3. I think your snippet should look like something like:
import React from 'react'
import { graphql, useStaticQuery } from 'gatsby'
import { getImage, GatsbyImage } from "gatsby-plugin-image"
import { convertToBgImage } from "gbimage-bridge"
import BackgroundImage from 'gatsby-background-image'
const GbiBridged = () => {
const { bgImage }= useStaticQuery(
graphql`
query {
bgImage : file(relativePath: {eq: "background.png"}) {
childImageSharp {
gatsbyImageData(quality: 90)
}
}
}
`
)
const image = getImage(bgImage)
const backgroundImage= convertToBgImage(image)
return (
<React.Fragment>
<GlobalStyle />
<BackgroundImage
Tag="section"
{...backgroundImage}
preserveStackingContext
>
<div style={{minHeight: 1000, minWidth: 1000}}>
<GatsbyImage image={image} alt={"testimage"}/>
</div>
</BackgroundImage>
</React.Fragment>
)
}
export default GbiBridged
Modified from: https://www.gatsbyjs.com/plugins/gatsby-background-image/#gatsby-34--gatsby-plugin-image applying your code
Gatsby changed the image plugin from gatsby-image (Gatsby 1 and 2) to gatsby-plugin-image (version 3 onwards). Among other things, it has changed the internal GraphQL nodes of the image data, hence the workaround of using gatsby-background-image has also changed accordingly. In your case, you are using the deprecated version of gatsby-image so your code is not able to display the image.
You can follow the full discussion in this GitHub thread: https://github.com/timhagn/gatsby-background-image/issues/141

I'd recommend not using any external plugins for this but using CSS to achieve this. This way you don't have to learn any new third-party plugins and can use the knowledge you have about CSS. Here's an example from the docs: https://www.gatsbyjs.com/docs/how-to/images-and-media/using-gatsby-plugin-image/#background-images
import * as React from "react"
import { StaticImage } from "gatsby-plugin-image"
export function Hero() {
return (
<div style={{ display: "grid" }}>
{/* You can use a GatsbyImage component if the image is dynamic */}
<StaticImage
style={{
gridArea: "1/1",
// You can set a maximum height for the image, if you wish.
// maxHeight: 600,
}}
layout="fullWidth"
// You can optionally force an aspect ratio for the generated image
aspectRatio={3 / 1}
// This is a presentational image, so the alt should be an empty string
alt=""
// Assisi, Perúgia, Itália by Bernardo Ferrari, via Unsplash
src={
"https://images.unsplash.com/photo-1604975999044-188783d54fb3?w=2589"
}
formats={["auto", "webp", "avif"]}
/>
<div
style={{
// By using the same grid area for both, they are stacked on top of each other
gridArea: "1/1",
position: "relative",
// This centers the other elements inside the hero component
placeItems: "center",
display: "grid",
}}
>
{/* Any content here will be centered in the component */}
<h1>Hero text</h1>
</div>
</div>
)
}

Related

react typescript stitches css prop problem, not work

i'm currently working on a project using stitches with cra but i've stuck to a problem with css props.
here's my code
Texts/index.tsx
import React from 'react';
import { TextStyle } from './textStyle';
const Texts = ({ text, css }: PropsType) => {
console.log(css);
return (
<>
<TextStyle css={{ ...css }} >
<>{text}</>
</TextStyle>
</>
);
};
export default Texts;
and this index.tsx is exported to another components
Container/index.tsx
import { styled, css } from '../../../stitches.config';
// atoms
import Texts from 'src/components/atoms/texts';
const PageContainer = () => {
return (
<Container>
<Contents >
<div>
<Texts
css={{ color: 'red' }}
/>
<Texts
css={{ paddingTop: '20px' }}
/>
</div>
</Contents>
</Container>
);
};
export default PageContainer;
as you can see with the above code, contains css as its child but css is never rendered at all
can anyone help me with this issue?
FYI, console.log(css); returned undefined to me.
Thank you in advance!

Basic Gatsby Shopify example missing Layouts

I am working with a basic Gatsby Shopify website template here https://www.gatsbyjs.com/docs/building-an-ecommerce-site-with-shopify/
I am trying to get this simple example up and running but I noticed in the following code block in
/src/pages/products.js
import Layout from "../components/layout"
there is no mention of components or layouts in the article and the app is throwing errors there. I am just trying to get a basic example to work. Is there a github link for this code?
The <Layout> component is a common resource in mostly all Gatsby starters (the default one for example), if you don't have it, just create the following structure under /components folder (to keep your code structure):
/**
* Layout component that queries for data
* with Gatsby's useStaticQuery component
*
* See: https://www.gatsbyjs.com/docs/use-static-query/
*/
import React from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"
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 || `Title`} />
<div
style={{
margin: `0 auto`,
maxWidth: 960,
padding: `0 1.0875rem 1.45rem`,
}}
>
<main>{children}</main>
<footer style={{
marginTop: `2rem`
}}>
© {new Date().getFullYear()}, Built with
{` `}
Gatsby
</footer>
</div>
</>
)
}
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default Layout
As you can see, the <Layout> component wraps the whole application with the children prop, sharing a <Header> component and a <footer> tag across all the applications when used.
You can remove propTypes if you are not using them.

Filter graphql data from frontend using react hooks

I have the following React page in Gatsby repo which runs a graphql page query to Netlify CMS to fetch the data :
import styled from 'styled-components';
import Layout from '../../components/Layout';
import Dropdown from '../../components/Dropdown';
import CardBlock from '../../components/creditcards/CardBlock';
import { graphql } from 'gatsby';
const CCListing = (response) => {
console.log("Credit Cards Listings")
console.log(response);
const {creditCards} = response.data;
return (
<CCListingContainer>
<Layout>
<div className="container">
<h1 className="section-title">Recommended cards for you</h1>
<h4 className="section-subtitle">Based on your answers, we’ve provided the top matches for you to compare below. Review and select the one that best matches your needs.</h4>
<div className="filters-container">
<Dropdown default="Travel" />
<Dropdown default="No Annul Fee" />
<Dropdown default="Welcome Bonus" />
<Dropdown default="Low to High" />
</div>
<div className="cards-container">
{creditCards.edges.map(item => (
<CardBlock cardData={item} />
))}
</div>
</div>
</Layout>
</CCListingContainer>
)
}
const CCListingContainer = styled.div`
.filters-container {
margin-top: 50px;
display: flex;
}
.cards-container {
margin-top: 2rem;
}
`
export const pageQuery = graphql`
query CreditCardListing {
creditCards:allMarkdownRemark(filter: {frontmatter:{ templateKey: { eq: "credit-card-post" } }}) {
edges {
node {
frontmatter {
title
cardImage {
childImageSharp {
fixed(width: 299, height: 189) {
...GatsbyImageSharpFixed
}
}
}
fee
purchaseInterest
cashAdvanceInterest
href
summaryDescription
}
}
}
}
}
`
export default CCListing;
On this page, I have these dropdowns at the top for filtering data coming from query :
How can I filter data based on dropdown selections ? Not sure how to introduce variables or react hooks in graphql query to make it dynamic.
It's a broad question and without having a CodeSandbox or something similar it's difficult to figure out how the code will behave. However, what you need to do, is to add the GraphQL query result to the state and then play with the state:
import styled from 'styled-components';
import Layout from '../../components/Layout';
import Dropdown from '../../components/Dropdown';
import CardBlock from '../../components/creditcards/CardBlock';
import { graphql } from 'gatsby';
const CCListing = (response) => {
console.log("Credit Cards Listings")
console.log(response);
const {creditCards} = response.data;
const [yourData, setYourData]= useState({}); // initially set to empty to avoid re-hydration issues or asynchronous execution issues if the data is empty
useEffect(() => {
setYourData(creditCards)
},[])
yourHandleFunction= ()=>{
// your stuff here. You may need to clone your state object and manipulate the copy, depending on your use-case.
}
return (
<CCListingContainer>
<Layout>
<div className="container">
<h1 className="section-title">Recommended cards for you</h1>
<h4 className="section-subtitle">Based on your answers, we’ve provided the top matches for you to compare below. Review and select the one that best matches your needs.</h4>
<div className="filters-container">
<Dropdown onClick={yourHandleFunction} default="Travel" />
<Dropdown onClick={yourHandleFunction} default="No Annul Fee" />
<Dropdown onClick={yourHandleFunction} default="Welcome Bonus" />
<Dropdown onClick={yourHandleFunction} default="Low to High" />
</div>
<div className="cards-container">
{creditCards.edges.map(item => (
<CardBlock cardData={item} />
))}
</div>
</div>
</Layout>
</CCListingContainer>
)
}
const CCListingContainer = styled.div`
.filters-container {
margin-top: 50px;
display: flex;
}
.cards-container {
margin-top: 2rem;
}
`
export const pageQuery = graphql`
query CreditCardListing {
creditCards:allMarkdownRemark(filter: {frontmatter:{ templateKey: { eq: "credit-card-post" } }}) {
edges {
node {
frontmatter {
title
cardImage {
childImageSharp {
fixed(width: 299, height: 189) {
...GatsbyImageSharpFixed
}
}
}
fee
purchaseInterest
cashAdvanceInterest
href
summaryDescription
}
}
}
}
}
`
export default CCListing;
It's quite self-explanatory. You need to set your state with useState (initially as empty to prevent any type of asynchronous execution that may break the code) and, once the DOM tree is loaded (useEffect with empty deps, []), your hook will fill your state with your GraphQL data with setYourData(creditCards).
The next step is to attach an onClick function event on your dropdowns and do your stuff there. Keep in mind that, depending on your needs and your use-case, you may need to copy the state object to avoid issues with your data. Something like this should work:
const clonedData = [...yourData]; // use {} if it's an object

Anchor Link under Map Component not clickable

I am writing my first React App (using create-react-app) and I wrote a Map component using google-maps-react. However, the links BELOW the map cannot be clicked.
Actually, on my webpage, this issue is present only on small and medium-sized screens, while it works perfectly on large screens (small, medium and large as defined by materializecss). I tried to reproduce the issue on a minimal working example, without materialize, just using the boilerplate code created by `npx create-react-app my-app' and adding the following:
MapComponent.js
import React from 'react';
import { Map, GoogleApiWrapper } from 'google-maps-react';
const mapStyles = {
width: '80vw',
height: '45vw',
marginLeft: 'auto',
marginRight: 'auto',
display: 'block'
};
const MapComponent = (props) => {
return (
<div className="MapComponent">
<div>
Google
</div>
<Map
google={props.google}
zoom={10}
style={mapStyles}
initialCenter={{
lat: 40,
lng: 12
}}
/>
<div>
Google
</div>
</div>
);
}
export default GoogleApiWrapper({
apiKey: "Key"
})(MapComponent);
and then in App.js:
import React, { Component } from 'react';
import MapComponent from './MapComponent';
class App extends Component {
render() {
return (
<div className="Appr">
<MapComponent />
</div>
);
}
}
export default App;
(the key is not reported in the example, so maps will display the frame with an error message, but the issue is the same with the key). The first link to google.com can be clicked and works, while the second does not. Any solution/workaround?
Finally, I went through the source code of google-maps-react and found the solution. It is very simple but rather undocumented. Apart from style the Map component accepts a containerStyle prop, allowing to change the tyle of the container wrapping Map. By default, the position is set to position: absolute giving the aforementioned behavior. The following code solves the issue for me:
import React from 'react';
import { Map, GoogleApiWrapper } from 'google-maps-react';
const mapStyles = {
width: '80vw',
height: '45vw',
marginLeft: 'auto',
marginRight: 'auto',
display: 'block'
};
const containerStyle = { {/* Added style */}
position: 'static'
}
const MapComponent = (props) => {
return (
<div className="MapComponent">
<div>
Google
</div>
<Map
google={props.google}
zoom={10}
style={mapStyles}
containerStyle={containerStyle} {/* Added prop */}
initialCenter={{
lat: 40,
lng: 12
}}
/>
<div>
Google
</div>
</div>
);
}
export default GoogleApiWrapper({
apiKey: "Key"
})(MapComponent);

how to use i18n to gatsby?

I have a problem with translations in my gatsby site.
I am using the i18n plugin to make translations but if i put in my index.jsx two FormattedMessage tag, it breaks my index.jsx.
I can find my issue in google but i can't figure out how to resolve it.
My index.jsx
import React from 'react'
import { FormattedMessage } from 'react-intl'
import Layout from '../components/Layout'
const IndexPage = ({ pathContext: { locale } }) => (
<Layout locale={locale}>
<FormattedMessage id="hello" />
<FormattedMessage id="hello" />
</Layout>
)
export default IndexPage
and my layout:
import React from 'react'
import PropTypes from 'prop-types'
import Helmet from 'react-helmet'
import { StaticQuery, graphql } from 'gatsby'
import Header from './header'
import './layout.css'
import { IntlProvider, addLocaleData } from 'react-intl'
// Locale data
import enData from 'react-intl/locale-data/en'
import ptData from 'react-intl/locale-data/pt'
import esData from 'react-intl/locale-data/es'
// Messages
import en from '../i18n/en.json'
import pt from '../i18n/pt.json'
import es from '../i18n/es.json'
const messages = { en, pt, es }
addLocaleData([...enData, ...ptData, ...esData])
const Layout = ({ locale, children }) => (
<StaticQuery
query={graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`}
render={data => (
<>
<Helmet
title={data.site.siteMetadata.title}
meta={[
{ name: 'description', content: 'Sample' },
{ name: 'keywords', content: 'sample, something' },
]}
>
<html lang="en" />
</Helmet>
<Header lang="/^\/eng/" />
<div
style={{
margin: '0 auto',
maxWidth: 960,
padding: '0px 1.0875rem 1.45rem',
paddingTop: 0,
}}
>
<IntlProvider locale={locale} messages={messages[locale]}>
{children}
</IntlProvider>
</div>
</>
)}
/>
)
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default Layout
I hope you can't help me to use more than one FormattedMessage tag for translations, thank you.
Maybe is not a valid solution for you but. Did you try gatsby-plugin-i18next? My first project with gatsbyjs was a nightmare deal with languages until I found it. In my opinion, it works really well. You must install it with npm/yarn and configure a little bit. You can remove the wrapper IntlProvider and you can take translations wherever you want (pages/templates or components).
Here and example extracted from your code (English & Spanish languages). The plugin take care of the URL, putting /es & /en in every pages/templates:
src/pages/index.jsx
import React from 'react';
import { I18n } from 'react-i18next';
import { withI18next } from 'gatsby-plugin-i18next';
import Layout from '../components/index'
const IndexPage = props => (<I18n>{t => (
<Layout{...props}>
<p>{t('hello')}</p>
<p>{t('hello')}</p>
</Layout>
)}</I18n>);
export const query = graphql`
query($lng: String!){
locales: allLocale(filter: { lng: { eq:$lng }, ns: { eq: "messages" } }) {
...TranslationFragment
}
}
`;
export default withI18next()(IndexPage);
src/components/index.jsx
Note that you must change Helmet as well. I translate the metadata in order to show how can translate in components (not pages neither templates).
import React from 'react';
import PropTypes from 'prop-types';
import { translate } from 'react-i18next';
import { Head } from 'gatsby-plugin-i18next';
import { StaticQuery, graphql } from 'gatsby'
import Header from './header'
import './layout.css'
const Layout = ({children, t }) => (
<StaticQuery
query={graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`}
render={data => (
<>
<Head hreflang>
<title>{data.site.siteMetadata.title}</title>
<meta name="description" content="{t('metaDescription')}" />
<meta name="keywords" content="{t('metaKeywords')}" />
</Head>
<Header lang="/^\/eng/" />
<div
style={{
margin: '0 auto',
maxWidth: 960,
padding: '0px 1.0875rem 1.45rem',
paddingTop: 0,
}}
>
{children}
</div>
</>
)}
/>
)
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default translate()(Layout)
gatsby-config.js
You can debug the plugin only when you are developing ;)
const defaultLanguage = "en";
const languages: ["en", "es"];
const siteUrl: "https://domain-where-the-gatsby-are-published.com/",
module.exports = {
...,
plugins: [
...,
{
resolve: `gatsby-plugin-i18next`,
options: {
availableLngs: languages,
fallbackLng: defaultLanguage,
debug: process.env.NODE_ENV === 'development',
siteUrl
},
}
],
}
locale/en/messages.json
{
"hello": "Hi!",
"metaDescription": "Sample page with i18n translations",
"metaKeywords": "i18n, gatsbyjs, english"
}
locale/es/messages.json
{
"hello": "Hola!",
"metaDescription": "Página de ejemplo con traducciones i18n",
"metaKeywords": "i18n, gatsbyjs, spanish"
}
As an extra comment:
Remember to change all the links imported from gatsby to
gatsby-plugin-i18next
You must inject the graphql query in every pages/templates
You can see the code of the starter to see how can you create a switcher between the languages

Resources