Gatsby: getImage returns undefined - javascript

getImage is returning undefined so my GatsbyImage component is not rendered.
File structure:
src/pages/gallery.js
src/images (has 12 photos named photo-01.jpg, photo-02.jpg, ...)
I have the following code (gallery.js):
import React from "react";
import Layout from "../components/Layout";
import { useStaticQuery, graphql } from "gatsby";
import { GatsbyImage, getImage } from "gatsby-plugin-image";
const Gallery = () => {
const { gallery } = useStaticQuery(graphql`
query {
gallery: allFile(
filter: {
extension: { eq: "jpg" }
absolutePath: { regex: "/images/" }
}
) {
nodes {
id
childImageSharp {
fluid(maxWidth: 500, maxHeight: 500) {
...GatsbyImageSharpFluid_tracedSVG
}
}
}
}
}
`);
return (
<Layout>
<div className="container py-5">
<div className="row">
<div className="col-12">
<h1 className="text-gastby mb-4">Gallery</h1>
</div>
</div>
<div className="row">
{gallery.nodes.map((image) => (
<div className="col-lg-3 col-md-4 col-sm-6 mb-3" key={image.id}>
<GatsbyImage
image={getImage(image.childImageSharp.fluid)}
alt="Gallery"
/>
</div>
))}
</div>
</div>
</Layout>
);
};
export default Gallery;
what can i have wrong?

The problem is that you are mixing gatsby-image (from Gatsby 1 to Gatsby 2) and gatsby-plugin-image (from Gatsby 3 onwards). The first one is now deprecated.
This can be easily spotted when you query for fluid or fixed GraphQL nodes since they are created by gatsby-image which uses Img (from 'gatsby-image') component, which accepts a fluid or fixed property.
On the other hand, gatsby-plugin-image queries for gatsbyImageData (not fluid or fixed) and the corresponding GatsbyImage (from 'gatsby-plugin-image') component accepts an image property.
In your case, you are querying a gatsby-image structure applied in a gatsby-plugin-image component, that's why it is returning undefined.
Check the migration guide but essentially you will need to replace (and remove) all references to gatsby-image and install the required dependencies:
npm install gatsby-plugin-image gatsby-plugin-sharp gatsby-transformer-sharp
Add it to your gatsby-config.js:
module.exports = {
plugins: [
`gatsby-plugin-image`,
`gatsby-plugin-sharp`,
`gatsby-transformer-sharp`,
],
}
And change your query to something like:
const Gallery = () => {
const { gallery } = useStaticQuery(graphql`
query {
gallery: allFile(
filter: {
extension: { eq: "jpg" }
absolutePath: { regex: "/images/" }
}
) {
nodes {
id
childImageSharp {
gatsbyImageData(layout: FIXED)
}
}
}
}
`);
return (
<Layout>
<div className="container py-5">
<div className="row">
<div className="col-12">
<h1 className="text-gastby mb-4">Gallery</h1>
</div>
</div>
<div className="row">
{gallery.nodes.map((image) => (
<div className="col-lg-3 col-md-4 col-sm-6 mb-3" key={image.id}>
<GatsbyImage
image={getImage(image.childImageSharp)}
alt="Gallery"
/>
</div>
))}
</div>
</div>
</Layout>
);
};
export default Gallery;
Double-check the query since the nodes and the structure may be different when applying gatsby-plugin-image.
Note that getImage is a helper function and you may not need it, consider using directly:
<GatsbyImage
image={image.childImageSharp.gatsbyImageData}
alt="Gallery"
/>

Related

How to filter array of fields on React-redux-firefbase

I am looking for a way to fetch some docs which contain some values of an array (e.g.)"stack" or "flow"
However, my code below didn't get any records.
import { firestoreConnect } from 'react-redux-firebase'
export default compose(
connect(mapStateToProps),firestoreConnect([{
collection : 'projects',
where:["tags", "array-contains-any", ["stack"]],
orderBy: ['createdAt', 'desc']
}])
)(Board);
I refer to this https://firebase.google.com/docs/firestore/query-data/queries
I found out when I changed the code. It works and shows the projects.
But I reloaded the browser the project was gone.
I also found that the parameters of firestoreConnect is less than 4, it wotks even if the page is refreshed.
Is there any alternative way?
//This code works anytime.
firestoreConnect([{
collection : 'projects',
where:["tags", "array-contains-any", ["stack"]],
orderBy: ['createdAt', 'desc']
}])
class Dashboard extends Component {
render() {
const { projects } = this.props;
return (
<div className="dashboard container">
<div className="row">
<div className="col s12 m6">
<ProjectList projects = {projects }/>
</div>
<div className="col s12 m5 offset-m1">
<Notifications />
</div>
</div>
</div>
);
}
}

Next.js markdown-blog page code not working

import { Blogs } from "../../components/Data"
import Image from "next/image";
import Link from "next/link";
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
export default function index({ posts }) {
// const Short_Blog = Blogs.map(item =>
// <div className="BLOGS_Projects" key={item}>
// <div className="BLOGS_Projects_Image">
// <Image
// className='BLOGS_Projects_image'
// src={item['img-1']}
// layout='fill'
// // objectFit='contain'
// />
// </div>
// {/* if someone clicks on this link i want them to go to [project].js and send This item to [projcet].js */}
// <Link href={'/blogs/' + Blogs.indexOf(item)}>
// <a>{item['title']}</a>
// </Link>
// <p>{item['desc']}</p>
// </div>
// );
return (
<div className="BLOGS_Container">
<div className="BLOGS_Sub_Container">
<div className="BLOGS_New">
<h1 style={{ marginLeft: 25 + 'px' }}>Cyber-Security Blogs</h1>
<div className="BLOGS_Present">
{posts.map( post =>{
<h1 style={{zIndex: '10000'}}>{post}</h1>
})}
</div>
</div>
</div>
</div>
)
}
export async function getStaticProps() {
const files = fs.readdirSync(path.join('posts'))
const posts = files.map((filename) => {
const slug = filename.replace('.md', '')
const markdownWithMeta = fs.readFileSync(path.join('posts', filename), 'utf-8')
const { data: frontmatter } = matter(markdownWithMeta)
return {
slug,
frontmatter
}
})
return {
props: {
posts,
},
}
}
The posts object does exist but when I try to use it in the HTML, it doesn't show up anyone got any idea why this is happening?
the posts.map that I used is not giving any errors but it also doesn't show any h1 html in actual page, the actual page seems blank.
You need to return the element to render inside the callback of map function.
1st way
{posts.map((post) => {
return <h1 style={{ zIndex: "10000" }}>{post}</h1>;
})}
2nd way
{posts.map((post) => (
<h1 style={{ zIndex: "10000" }}>{post}</h1>
))}
React will not render plain html content as a string. You need to use the dangerouslySetInnerHTML prop, like so:
{
posts.map((post) => {
return <div dangerouslySetInnerHTML={{__html: post}}></div>
})
}
You can read more about it here:
https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
Alternatively you can use something like next-mdx-remote, which you can learn about here:
https://github.com/hashicorp/next-mdx-remote

Routing not working using Gatsby - reach-router

I'm trying to render a blog as a card then open it up as a page , but its proving to be difficult using Gatsby. I did the exact same thing fine with react using React router but it doesn't seem to be working with Gatsby. I know I can use GraphQL but surely I can do the same thing using REST. Im using Contentful btw
I switched to reach router as suggested in another post but that doesnt work.
I kept getting this error when I used react-router-dom:
Invariant failed: You should not use <Link> outside a <Router>
Fetching Blog contents
function Blog() {
const [blogs, setBlogs] = useState([])
const [image, setImage] = useState()
const [selectedBlog, setSelectedBlog] = useState(blogs)
useEffect(() => {
fetch("http://cdn.contentful.com...")
.then(response => response.json())
.then(data =>
setBlogs(data.items)
)
}, [])
console.log(blogs)
return (
<>
<div className="card-flex" >
{selectedBlog !== null ? blogs.map((blog =>
<Card title={blog.fields.title} date={blog.fields.date} introduction={blog.fields.introduction} mainBody1={blog.fields.mainBody1} mainBody2={blog.fields.mainBody2} setSelectedBlog={selectedBlog}
/>
)):
<Article title={blogs.find(d => d.fields.title === selectedBlog)} />
}
</div>
</>
)
}
export default Blog
Blog Card
function Card(props) {
console.log(props)
return (
<div class="container">
<div class="card">
<div class="card-header">
<img style={{backgroundImage: "url('https://i.pinimg.com/564x/7f/bb/97/7fbb9793b574c32f5d28cae0ea5c557f.jpg')"}}/>
</div>
<div class="card-body">
<span class="tag tag-teal">{props.tags}</span>
<h4>{props.title}</h4>
<p style={{fontSize:"17px", paddingTop:"10px"}} >{props.introduction}</p>
<div class="card-user">
<Link
to={{
pathname: '/article',
state: {
title: props.title,
introduction: props.introduction
}
}}
>
<button>read more</button>
</Link>
<div class="user-info">
<h5 >{ props.date}</h5>
</div>
</div>
</div>
</div>
</div>
)
}
export default Card
**Article **
import React from 'react'
import './Article.css'
import { useLocation } from "#reach/router"
function Article(props) {
// useLocation to access the route state from Blog.js
const { state = {} } = useLocation();
console.log(state)
return (
<div className="main">
<h1 className="title">{state.title}</h1>
<p className="intro">{state.introduction}</p>
<p className="main1">{state.mainBody1}</p>
<p className="main2">{state.mainBody2}</p>
</div>
)
}
export default Article
I think you are mixing stuff. Gatsby extends from #reach/router so you don't need to use its notation. Your Link should look like:
<Link
to={`/article`}
state={{
title: props.title,
introduction: props.introduction
}}
>
Assuming your /article page exists under /pages folder.

Conditional rendering in React + Gatsby Static Query + GraphQL

I want to choose just featured posts (3 posts) from graphql for then show this in my blog page, so I limit query to only three results but in case that I just have one post the site will fail.
Because, I'm using a staticquery for get data, in this case I should to use render attribute in the staticquery component and I can not to use a if block on the attribute and when graphql won't find other posts it gonna fail.
Here the code:
featured-posts.js
import React from "react"
import MiniFeatured from "../components/minifeatured"
import { StaticQuery, Link, graphql } from "gatsby"
const Featured = () => {
return (
<StaticQuery
query={graphql`
query FeaturedBlogsport {
allMarkdownRemark (
limit: 3
sort: {order: DESC, fields: [frontmatter___date]}
filter: {frontmatter: {featured: {eq: true}}}
) {
edges {
node {
frontmatter {
title
description
post_image
}
fields {
slug
}
}
}
}
}
`}
render={data => (
<div className="mainBlogposts">
<div
className="featuredBlogpost"
style={{backgroundImage: `url('${data.allMarkdownRemark.edges[0].node.frontmatter.post_image}')`}}
>
<div className="featuredBlogpostContent">
<Link to={`https://strokequote.co/${data.allMarkdownRemark.edges[0].node.fields.slug}`}>
<h1 className="featuredBlogpostTitle">
{data.allMarkdownRemark.edges[0].node.frontmatter.title}
</h1>
<h6 className="featuredBlogpostAuthor">
{data.allMarkdownRemark.edges[0].node.frontmatter.description}
</h6>
</Link>
</div>
</div>
<div className="minifeaturedBlogpostsContainer">
<MiniFeatured
title={data.allMarkdownRemark.edges[1].node.frontmatter.title}
description={data.allMarkdownRemark.edges[1].node.frontmatter.description}
postImage={data.allMarkdownRemark.edges[1].node.frontmatter.post_image}
slug={data.allMarkdownRemark.edges[1].node.fields.slug}
/>
<MiniFeatured
title={data.allMarkdownRemark.edges[2].node.frontmatter.title}
description={data.allMarkdownRemark.edges[2].node.frontmatter.description}
postImage={data.allMarkdownRemark.edges[2].node.frontmatter.post_image}
slug={data.allMarkdownRemark.edges[2].node.fields.slug}
/>
</div>
</div>
)}
/>
)
}
export default Featured
PDD. Minifeatured are secondary featured posts in other components.
PDD 2. Sorry about my English, I'm still learning
I believe that find found a solution. With useStaticQuery from gatsby I can do something like this:
const Featured = () => {
const { edges } = FeaturedPostsQuery()
return (
<div className="mainBlogposts">
<div
className="featuredBlogpost"
style={{backgroundImage: `url('${edges[0].node.frontmatter.post_image}')`}}
>
<div className="featuredBlogpostContent">
<Link to={`https://strokequote.co/${edges[0].node.fields.slug}`}>
<h1 className="featuredBlogpostTitle">
{edges[0].node.frontmatter.title}
</h1>
<h6 className="featuredBlogpostAuthor">
{edges[0].node.frontmatter.description}
</h6>
</Link>
</div>
</div>
<div className="minifeaturedBlogpostsContainer">
<MiniFeatured
title={edges[1].node.frontmatter.title}
description={edges[1].node.frontmatter.description}
postImage={edges[1].node.frontmatter.post_image}
slug={edges[1].node.fields.slug}
/>
<MiniFeatured
title={edges[2].node.frontmatter.title}
description={edges[2].node.frontmatter.description}
postImage={edges[2].node.frontmatter.post_image}
slug={edges[2].node.fields.slug}
/>
</div>
</div>
)
}
export default Featured
export const FeaturedPostsQuery = () => {
const { allMarkdownRemark } = useStaticQuery(graphql`
query FeaturedBlogsport {
allMarkdownRemark (
limit: 3
sort: {order: DESC, fields: [frontmatter___date]}
filter: {frontmatter: {featured: {eq: true}}}
) {
edges {
node {
frontmatter {
title
description
post_image
}
fields {
slug
}
}
}
}
}
`)
return allMarkdownRemark
}
Why do you use a StaticQuery to achieve this? You can simply do it by using a regular GraphQL query, like:
import { graphql, Link } from 'gatsby';
import React from 'react';
const Featured = ({ data }) => {
return <div>
{data.allMarkdownRemark.edges.map(({ node: post }) => {
return <div className="mainBlogposts">
<div className="featuredBlogpost"
style={{ backgroundImage: `url(${post.frontmatter.post_image})` }}>
<div className="featuredBlogpostContent">
<Link to={`https://strokequote.co/${post.fields.slug}`}>
<h1 className="featuredBlogpostTitle">
{post.frontmatter.title}
</h1>
<h6 className="featuredBlogpostAuthor">
{post.frontmatter.description}
</h6>
</Link>
</div>
</div>
</div>;
})}
</div>;
};
export const AboutMeData = graphql`
query FeaturedBlogsport {
allMarkdownRemark (
limit: 3
sort: {order: DESC, fields: [frontmatter___date]}
filter: {frontmatter: {featured: {eq: true}}}
) {
edges {
node {
frontmatter {
title
description
post_image
}
fields {
slug
}
}
}
}
}
`;
What I've done is simply get all the 3 articles and loop through them, using your HTML structure. I aliased the node as a post using a destructuring inside the iterable variable in { node: post } but ideally, all that bunch of HTML should be another isolated component (it's really huge) and you should pass post as a prop to them but for now, it will work.
The snippet above will simply print the amount of post that the query can fetch, no matter if it's 1, 2, or 3.
Besides, it's cleaner than accessing manually each array position ([0], [1], etc).

Map inside map in react ( one is local array of images and the other is title from json )

As being designer and novice to react, I developed code in which local array is displaying as image and json data as title. Titles are working fine but images are not displaying and showing all of arrays in src attribute.
I have used Axios.get() to fetch data from the server.
I am missing out in logic somewhere while developing map inside map. I would be grateful for getting help.
EDIT : I want one image with one title.
CommonMeds.js
import React, { Component } from 'react';
import './CommonMeds.scss';
import MedSection from '../../Components/MedSection/MedSection';
import Axios from 'axios';
class CommonMeds extends Component {
state = {
MedTitle: [],
TitleImg: [
{ imageSrc: require('../../../../images/medstype_1.svg') },
{ imageSrc: require('../../../../images/medstype_2.svg') },
{ imageSrc: require('../../../../images/medstype_3.svg') },
{ imageSrc: require('../../../../images/medstype_4.svg') },
{ imageSrc: require('../../../../images/medstype_5.svg') },
{ imageSrc: require('../../../../images/medstype_6.svg') },
{ imageSrc: require('../../../../images/medstype_7.svg') },
{ imageSrc: require('../../../../images/medstype_8.svg') },
{ imageSrc: require('../../../../images/medstype_9.svg') },
{ imageSrc: require('../../../../images/medstype_10.svg') },
]
};
componentDidMount() {
const medInfo = Axios.get('URL OF JSON DATA');
medInfo.then( response => {
this.setState({MedTitle: response.data.result});
});
}
render() {
const Meds = this.state.MedTitle.map(med => {
const imglable = this.state.TitleImg.map(src => {
return src.imageSrc;
})
return <MedSection
Title={med.medicationCategory}
src = {imglable}
/>;
});
return(
<div className="container">
<h3 className="text-left">Common Medicines with Categories</h3>
<hr />
{Meds}
</div>
);
}
}
export default CommonMeds;
MedSection.js
import React from 'react';
import './MedSection.scss';
import MedicineList from '../MedicineList/MedicineList';
const MedSection = (props) => {
return (
<div className="col-12">
<div className="row">
<div className="col-12 col-md-3 col-lg-2 px-0">
<div className="c-medsimg-box py-4 px-2">
<img src={props.src} alt="Medication Type Icon" className="img-fluid" />
<h5 className="mt-3" key={props.key}>{props.Title}</h5>
</div>
</div>
<div className="col-12 col-md-9 col-lg-10">
<div className="h-100 d-flex align-items-center">
<ul className="c-medslist-ul pl-0 mb-0">
<MedicineList />
</ul>
</div>
</div>
</div>
<hr />
</div>
)
}
export default MedSection;
You are currently creating an array of images for each MedTitle. You could instead take the entry from TitleImage that has the same index as the current med in your loop instead.
You can also make it safe by using the % operator, so that if your MedTitle array is larger than your TitleImage array, you will still get an image.
const Meds = this.state.MedTitle.map((med, index) => {
const src = this.state.TitleImg[index % this.state.TitleImg.length].imageSrc;
return <MedSection Title={med.medicationCategory} src={src} />;
});
As long as length of both arrays are same, it will work.
Try using this.
const imglable = this.state.TitleImg.map(src => {
return src.imageSrc;
})
const Meds = this.state.MedTitle.map((med, index) => {
return <MedSection
Title={med.medicationCategory}
src = {imglable[index]}
/>;
});

Categories

Resources