How to map graphQL sub property - javascript

I want to turn my Wordpress Blog into a react app through Hygraph headless CMS.
My API query has "wordPressPosts" posts within a master "posts" property.
const { posts } = await hygraph.request(
`
{
posts {
wordPressPosts {
id
title {
rendered
}
categories
}
}
}
`
);
How can I access wordPressPosts "ids" and post "titles" to map them? I tried messing with posts.wordPressPosts but it does not display anything on screen.
return {
props: {
posts
}
};
}
export default ({ posts }) =>
posts.map(({ id, title }) => <p key={id}>{title}</p>);
Full code sandbox: https://codesandbox.io/s/wp-source-for-hygraph-li2ssl?file=/src/pages/index.js
Cheers,
L.

Related

Fetch only one element from Graphql in Gatsby

am new to gatsby and graphql and I came across a tutorial where it is mentioned to fetch all the data using .map. But I want to fetch only one element from the DB. So how do I do it?
import React from "react";
import Layout from "../components/layout";
import { useStaticQuery, graphql, Link } from "gatsby";
const Blogs = () => {
const data = useStaticQuery(
graphql`
query {
allMarkdownRemark(sort: { frontmatter: { date: ASC } }) {
edges {
node {
frontmatter {
title
date(formatString: "DD MM, YYYY")
}
excerpt
id
fields {
slug
}
}
}
}
}
`
);
return (
<Layout>
<ul>
{data.allMarkdownRemark.edges.map((edge) => {
return (
<li key={edge.node.id}>
<h2>
<Link to={`/blog/${edge.node.fields.slug}/`}>
{edge.node.frontmatter.title}
</Link>
</h2>
<div>
<span>
Posted on {edge.node.frontmatter.date}
</span>
</div>
<p>{edge.node.excerpt}</p>
<div>
<Link to={`/blog/${edge.node.fields.slug}/`}>Read More</Link>
</div>
</li>
);
})}
</ul>
</Layout>
);
};
export default Blogs;
Lets say I have multiple blogs and I wish to show only a specific one in a page through query like...
query MyQuery {
markdownRemark((id: {eq: "9ac19d6d"}) //Some ID {
title
description
content
}
}
How to get this on a page to display?
Thanks in advance!
Depending on what do you want to achieve:
If you want just a specific single post. You can filter your useStaticQuery to add the value of the id (if you know it beforehand) like:
query MyQuery {
markdownRemark((id: {eq: "123"}) {
title
description
content
}
}
useStaticQuery as the name points out, is static and doesn't accept dynamic values.
Another alternative is to get a specific position from data.allMarkdownRemark to display it.
If you just want a single post without any filter you can take advantage of the GraphQL query options:
{
allMarkdownRemark(limit: 1) {
edges {
node {
frontmatter {
title
}
}
}
}
}
If you are trying to create dynamic posts, hence each post template will display a different blog post (one per template), you need to pass a filter value from gatsby-node.js (where you create the post pages) to the template through Gatsby's context:
// gatsby-node.js
posts.forEach(({ node }, index) => {
createPage({
path: node.fields.slug,
component: path.resolve(`./src/templates/blog-post.js`),
context: {
id: node.id,
title: node.title
},
})
})
Note: here I'm lifting the id and the title. Use whatever works better for you
Now, you can take advantage of the context in your Blogs component (as long as it's a template):
const Blogs = ({data}) => {
console.log("your blog post is:", data)
return (
<Layout>
<h1>{data.markdownRemark.title}</h1>
</Layout>
);
};
export const query = graphql`
query($id: String!, $title: String!) {
markdownRemark((id: {eq: $id}) {
title
description
content
}
}
`
export default Blogs;
In other words: the first approach uses a static query (via useStaticQuery hook. Static, no dynamic parameters allowed) and the second uses a page query (only available in pages or templates)
With your query:
query MyQuery {
markdownRemark((id: {eq: "9ac19d6d"}) //Some ID {
title
description
content
}
}
Your data will be in data.markdownRemark
You can access those 3 fields directly.
const { title, description, content ] = data.markdownRemark;
return (
<Layout>
<div>
<p>{title}</p>
<p>{description]</p>
<p>{content}</p>
</div>
</Layout>
)

Dynamically rendered images in Gatsby

I'm working on the blog based on React, TS and Gatsby.
Blog posts are based on markdown. Each blog post will have a similar header with title, time necessary to read the article and the logos of the technologies that the particular blog post will be about.
I have a problem with rendering those images dynamically. My idea was to create something like this in markdown
---
path: "/fourth"
date: "2021-06-02"
title: "TypeScript - intro"
readTime: "140"
author: "Adam Kniec"
imgs: [typescript, react]
---
That's the fourth blog post
after that I wanted to create a graphql query and get the imgs names like so:
export const postQuery = graphql`
query BlogPostByPath($path: String!) {
markdownRemark(frontmatter: { path: { eq: $path } }) {
html
frontmatter {
path
readTime
title
author
imgs
date
}
}
}
`;
I have the array of images in the props now and I wanted to render those images like this
{data.markdownRemark.frontmatter.imgs.map((imgPath) => {
const imgPatha = `../images/${imgPath}`;
return <StaticImage src={imgPatha} alt="asdasd" />;
})}
Unfortunately, gatsby gives me the warning
react_devtools_backend.js:2560 Image not loaded ../images/typescript
Is this the correct approach ? Please let me know what I'm doing wrong or how to render those images dynamically.
As it has been said by #coreyward you can't use dynamic props in the StaticImage component, it's a known restriction.
That said, you have two choices:
Using the standard img HTML tag.
Using the GatsbyImage component. To do it, you'll need to add the images in your filesystem to allow Gatsby to create the proper nodes and then, you will need to query them in your pages/templates. Without further details on the implementation, it's impossible to guess how your code should look like but the idea relies on something like:
import { graphql } from "gatsby"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
function BlogPost({ data }) {
const image = getImage(data.blogPost.avatar)
return (
<section>
<h2>{data.blogPost.title}</h2>
<GatsbyImage image={image} alt={data.blogPost.author} />
<p>{data.blogPost.body}</p>
</section>
)
}
export const pageQuery = graphql`
query {
blogPost(id: { eq: $Id }) {
title
body
author
avatar {
childImageSharp {
gatsbyImageData(
width: 200
placeholder: BLURRED
formats: [AUTO, WEBP, AVIF]
)
}
}
}
}
`

GraphQL Query to Array List using React?

I am currently working on a gatsby website and am mostly using react components doing so. The way our jobs posting page currently works is that it fetches a list of jobs from an array that stores the information for each position and maps them out with proper stylization.
positions.js (section)
const Positions = () => (
<StyledPositions>
<GlobalContainer>
{PositionList.map((position, index) => (
<StyledPosition key={index}>
<StyledPositionName>
<Link to={position.link} activeClassName="active">
{position.name}
</Link>
</StyledPositionName>
</StyledPosition>
))}
</GlobalContainer>
</StyledPositions>
);
export default Positions;
PositionList is the array and it looks like this.
positionslist.js
const Positionlist = [
{
name: "Senior Software Engineer- Infrastructure",
link: "/careers/open_positions/sr_cloud_eng",
},
{
name: "System Software Engineer",
link: "/careers/open_positions/system_soft_eng",
},
{
name: "Software Engineer (Database Development)",
link: "/careers/open_positions/soft_eng_database",
},
];
export default Positionlist;
What I'm trying to do is to populate the job posting site from a GraphQL query from an external job posting management site. I am able to fetch the information fine, but I'd like to somehow turn the information into an array like positionslist.js so that positions.js can simply map the information the same way. The query looks like this
query MyQuery {
allLever {
edges {
node {
text
categories {
commitment
location
team
}
applyUrl
}
}
}
}
All GraphQL queries store their result inside props.data as you can see in Gatsby's tutorial. At this point, you only need to enter to the nested structure like:
import * as React from 'react'
import { graphql } from 'gatsby'
const Positions = ({data}) => {
let PositionList = data.edges;
return <StyledPositions>
<GlobalContainer>
{PositionList.map(({node: position}) => (
<StyledPosition key={position.name}>
<StyledPositionName>
<Link to={position.link} activeClassName="active">
{position.name}
</Link>
</StyledPositionName>
</StyledPosition>
))}
</GlobalContainer>
</StyledPositions>
}
export const query = graphql`
query MyQuery {
allLever {
edges {
node {
name: text
categories {
commitment
location
team
}
link: applyUrl
}
}
}
}
`
export default Positions
Note: it's better to avoid using index as key so you can use another field
Keep in mind that you barely need to change your previous structure (because of some destructuring + aliasing) but, what's important is that page queries, only work in pages (hence the name) so I'm assuming that Positions is a separate page. Otherwise, you will need to pass down the props from the page component.
Because of the aliasing, applyUrl will be aliased as link and text to name, so your previous structure will work exactly in the same way.

GatsbyJS - TypeError: Cannot read property 'childImageFluid' of undefined

I am working on a Gatsby website, and I keep getting "TypeError: Cannot read property 'childImageFluid' of undefined"
The code I have is this in my Project.js file
import React from "react"
import PropTypes from "prop-types"
import Image from "gatsby-image"
import { FaGithubSquare, FaShareSquare } from "react-icons/fa"
const Project = ({description, title, github, stack, url, image, index}) => {
return (
<article className="project">
<Image fluid={image.childImageFluid.fluid} className="project-img" />
</article>
)
}
Project.propTypes = {}
export default Project
and I have the graphql set up in the index.js file where it will be displayed, and everything is working as it should in graphql...
export const query = graphql`
{
allStrapiProjects(filter: { featured: { eq: true } }) {
nodes {
github
id
description
title
url
image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
stack {
id
title
}
}
}
}
`
everything up to the what I am working on in the Project.js file is in my github - https://github.com/matthewbert86/gatsby-site but all of that code is in the first code section above.
When you use a page query in GraphQL, your gathered data is stored inside a data object (as a props). You need to iterate through it until you get your fluid image. It should be in: props.data.allStrapiProjects.nodes.image.childImageFluid.fluid. Since you are destructuring everything in your <Project> component:
const Project = ({ data }) => {
let { description, title, github, stack, url, image } = data.allStrapiProjects.nodes; // your data is here
return (
<article className="project">
<Img fluid={data.allStrapiProjects.nodes.image.childImageFluid.fluid} className="project-img" />
</article>
)
}
After destructuring, you can refactor it to:
<Img fluid={image.childImageFluid.fluid} className="project-img" />
Another point, I guess that the gatsby-image import should be Img, not Image.

How to fix "Unknown argument 'slug' " in gatsbyjs?

I am currently trying to create a blog site using gatsbyjs, and would like my blog posts to have their pages created for them programmatically.
I followed the steps in the tutorials section of the official documentation, but instead of creating the pages from a markdown file, I am pulling data from the contentful CMS. I keep on hitting this block whenever I run my code.
gatsby-node.js
const path= require('path')
exports.createPages=({graphql,actions})=>{
const {createPage}=actions
const blogPost= path.resolve('./src/components/blogComponents/blog-post.js')
return new Promise((resolve,reject)=>{
graphql(`
{
allContentfulBlog{
edges{
node{
slug
}
}
}
}
`).then(results=>{
// console.log(results)
if(results.error){
reject(results.error)
}
// create blog post pages
const posts=results.data.allContentfulBlog.edges
posts.forEach((post,index)=>{
console.log(`showing slugs: ${post.node.slug}`)
createPage({
path:post.node.slug,
component:blogPost ,
context:{
slug:post.node.slug,
}
})
})
}).then(resolve)
})
}
blog-post.js
import React from 'react'
import { graphql} from 'gatsby'
const blogPost=({data})=>{
return (
<div>
new page created
</div>
)
}
export default blogPost
export const pageQuery= graphql`
query ($slug: String!){
allContentfulBlog (slug:{eq: $slug }) {
edges{
node{
content{
content
}
}
}
}
}
`
I expected the blog-post.js file to receive all appropriate variables, but instead, it kept on throwing the "unknown argument 'slug' " error while making reference to the blog-post.js file.
In blog-post.js, it looks like you might have been filtering the posts incorrectly; either do this:
export const pageQuery= graphql`
query ($slug: String!){
- allContentfulBlog (slug:{eq: $slug }) {
+ allContentfulBlog (filter: { slug: { eq: $slug } })
edges {
node {
content {
content
}
}
}
}
}
`
Or this:
export const pageQuery= graphql`
query ($slug: String!){
- allContentfulBlog (slug:{eq: $slug }) {
+ ContentfulBlog (slug:{eq: $slug }) {
content {
content
}
}
}
`

Categories