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
Related
I tried implementing browser router, but to no success. i'm having trouble with useParams hook, and just the router in general. Looked through multiple posts and i just wasn't able to get it working. I'll post the most barebones code below, hoping someone knows the solution. I removed the traces of the router, since it didn't work.
App.js is currently empty:
const App=()=> {
return (
<Main/>
);
}
Main.jsx is my main element, where components change. There isn't a page change per se, everything is in the main element. values get passed through props into main and written into state, so the useEffect can change visibility of components based on what you chose, first category, then recipe.:
const Main =()=> {
const [showElement, setShowElement] = useState("category");
const [selectedCategory, setSelectedCategory] = useState();
const [selectedRecipe, setSelectedRecipe] = useState();
useEffect(()=> {
if (selectedRecipe) {
setShowElement("recipe")
} else if (selectedCategory) {
setShowElement("recipeSelection")
}
window.scrollTo(0, 0)
}, [selectedCategory][selectedRecipe]);
return (
<>
<Header />
<main className="main">
<div>
<div>
{showElement === "category" &&
<CategoryWindow
passSelectedCategory={setSelectedCategory}
/>
}
</div>
<div>
{showElement === "recipeSelection" &&
<RecipeSelection
value={selectedCategory}
passSelectedRecipe={setSelectedRecipe}
/>
}
</div>
<div>
{showElement === "recipe" &&
<RecipeWindow
value={selectedRecipe}
/>
}
</div>
</div>
</main>
</>
)
}
This is the recipe picker component. For example when i click on curry, i'd like the url to show /food/curry. None od the names are hardcoded, everything comes from a javascript object:
const RecipeSelection =(props)=> {
const recipies = Recipies.filter(x=>x.type === props.value);
return (
<div className="selection-div">
<div className="selection-inner">
{recipies.map(selection =>
<>
<img src={require(`../images/${selection.id}.png`)}
className="selection-single"
key={selection.id}
alt={"picture of " + selection.id}
onClick={()=> props.passSelectedRecipe(selection.id)}
>
</img>
<div className="container-h3"
onClick={()=> props.passSelectedRecipe(selection.id)}
>
<h3 className="selection-h3">{selection.name}</h3>
</div>
</>
)}
</div>
</div>
)
}
This question already has an answer here:
How to add new pages without rebuilding an app with +150k static pages?
(1 answer)
Closed 11 months ago.
I've jus started working and learning Next so I have a lot of confusions,
I was using the useEffect on react and it always updated the UI with the new stuff that was added to the API however, its not working on next.js
SO I have an index file
import Link from "next/link";
import react, {useState, useEffect} from "react";
import { useRouter } from 'next/router';
export async function getStaticProps({ res }) {
try {
const result = await fetch(`https://api.pandascore.co/matches/running??sort=&page=1&per_page=10&&token=#`);
const data = await result.json();
return {
props: { game: data },
revalidate: 10 // 10 seconds
};
} catch (error) {
res.statusCode = 404;
return { props: {} };
}
}
const upcomingGames = ({ game }) => {
return (
<div className="container">
<h2>Live Games - </h2>
<div className="columns is-multiline">
{game.map(q => (
<div className="column is-half" key={q.id}>
<div className="inner">
<div className="inner__box">
<Link href = {'/live/' + q.slug} key={q.slug}>
<a className="h2link" key={q.slug}> {q.name}</a>
</Link></div>
</div>
</div>
))}
</div>
</div>
);
}
export default upcomingGames;
This file is connected to a [slug].js file which displays more details about a game,
Now in production when I deployed the app to vercel I have noticed that when a new game is added to the API it displays in the index.js but when I click on it I'm redirected to a fallback(404) page.
After I redeploy my project this is fixed, however every time a new game is added and rendered I'm unable to access its individual page which I defined in [slug].js
export const getStaticPaths = async () => {
const res = await fetch(`https://api.pandascore.co/matches/running?sort=&page=1&per_page=50&token=#`);
const data = await res.json();
const paths = data.map(o => {
return {
params: { slug: o.slug.toString() }
}
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const slug = context.params.slug;
const res = await fetch(`https://api.pandascore.co/matches/running?search[slug]=${slug}&token=#`);
const data = await res.json();
console.log(data)
return {
props: {
game: data
}
}
}
export default function live({ game }) {
return (
<div className="container">
<h2> Single Game deets.</h2>
{game.map((g) => (
<div className="container" key={g.id} >
<div className="inner-box" key={g.slug}>
{/** Fetch team and display their corresponding score - A bit of code repition :( */}
<div className="score-board-min columns is-mobile is-multiline">
<div className="column is-full"> {g.opponents.slice(0, -1).map((o) => <span className="team" key={o.id}>{o.opponent.name}</span>)}
{g.results.slice(0, -1).map((res, i) => (
<span className="scores" key={i}>{res.score}</span>
))}</div>
<div className="column">
{g.opponents.slice(-1).map((o) => <span className="team" key={o.id}>{o.opponent.name}</span>)}
{g.results.slice(-1).map((res, i) => (
<span className="scores" key={i}><div>{res.score}</div></span>
))}
</div>
</div>
<br />
<div className="lower-box columns is-multine">
<div className="column is-half">
<div className="dark"><span className="is-pulled-left">League</span> <span className="is-pulled-right">{g.league && g.league.name}</span></div>
<div className="dark"><span className="is-pulled-left">Game:</span> <span className="is-pulled-right"> {g.videogame && g.videogame.name} </span></div>
<div className="dark alt"><span className="is-pulled-left">Tournament</span> <span className="is-pulled-right"> {g.tournament && g.tournament.name} | </span></div>
<div className="dark"><span className="is-pulled-left">Series</span> <span className="is-pulled-right"> {g.serie.full_name} | {g.serie.tier.toUpperCase()} </span></div>
<div className="dark alt"><span className="is-pulled-left">Teams</span> <span className="is-pulled-right"> {g.opponents.map((o) => o.opponent.name).join(" vs ")} </span></div>
</div>
</div>
<br />
</div>
</div>
))}
</div>
)
}
During development (next dev) getStaticPaths gets called on every request, but for production it only gets called the next time you run next build. So when a new game is added to the API, the paths named after ${some_new_game_slug} won't exist until you run next build again, i.e., re-deploy. If this type of data changes frequently, you might have to use getServerSideProps for [slug].js as well (so no static paths) or opt for the client-side data fetching approach.
I am building a gallery where you click on the image and it will load in a separate component using props, this image is a URL, taken from a hard-coded array, where the src is loaded as a background image via CSS. My challenge is connecting the data to that component. I have tried connecting the data from parent to child with callbacks, but no luck. I think what I am trying to do is connect components sideways, and I don't want to use redux, as I am not familiar.
Note: I am aware you can just load the image in GalleryContainer.js using window.location.href = "props.src/", however, I want the image to load in the Image component that will act as a container to hold the image giving the user other options such as downloading the image, etc...
Note: I have tried importing the Image component in Gallery.js and rendering it like so: <Image src={props.src} id={props.id}/>, and I find the data connects just fine, but this does not help keep the component separate.
What I have already :
I have a route in app.js that allows me to go to the image route path just fine it’s loading in the url from props.src in the image component that is my challenge
UPDATE: SOLVED Click here to see the solution!
Here is the code:
GalleryList.js
import Gallery from "./Gallery";
import Header from "./UI/Header";
import Footer from "./UI/Footer";
import styles from "./Gallery.module.css";
const DUMMY_IMAGES = [
{
id: "img1",
src: "https://photos.smugmug.com/photos/i-vbN8fNz/1/X3/i-vbN8fNz-X3.jpg",
},
{
id: "img2",
src: "https://photos.smugmug.com/photos/i-fSkvQJS/1/X3/i-fSkvQJS-X3.jpg",
},
{
id: "img3",
src: "https://photos.smugmug.com/photos/i-pS99jb4/0/X3/i-pS99jb4-X3.jpg",
},
];
const GalleryList = () => {
const imagesList = DUMMY_IMAGES.map((image) => (
<Gallery id={image.id} key={image.id} src={image.src} />
));
return (
<>
<Header />
<ul className={styles.wrapper}>
<li className={styles.list}>{imagesList}</li>
</ul>
Home
<Footer />
</>
);
};
export default GalleryList;
Gallery.js
import GalleryConatiner from "./UI/GalleryContainer";
import styles from "./Gallery.module.css";
const Gallery = (props) => {
return (
<>
<div className={styles["gal-warp"]}>
<GalleryConatiner id={props.id} key={props.id} src={props.src} />
</div>
</>
);
};
export default Gallery;
GalleryContainer.js
import styles from "../Gallery.module.css";
const GalleryConatiner = (props) => {
const selectedImg = () => {
if (props.id) {
// window.location.href = `image/${props.src}`;
window.location.href = "image/"
}
};
return (
<ul>
<li className={styles["gallery-list"]}>
<div
onClick={selectedImg}
className={styles["div-gallery"]}
style={{
backgroundImage: `url(${props.src}`,
height: 250,
backgroundSize: "cover",
}}
></div>
</li>
</ul>
);
};
export default GalleryConatiner;
Image.js
import styles from "./Image.module.css";
const Image = (props) => {
return (
<section>
<h1 className={styles["h1-wrapper"]}>Image:{props.id}</h1>
<div className={styles.wrapper}>
<div
className={styles["image-container"]}
style={{
backgroundImage: `url(${props.src}`,
}}
></div>
</div>
</section>
);
};
export default Image;
You should be able to use the router Link to pass data via "state" on the to property.
From React Router's documentation:
<Link
to={{
pathname: "/images",
state: { imgUrl: props.src }
}}
/>
I have been using react for sometime,I decided to try out nextjs. I am building a dashboard, that have a side navigation, and several pages will use that sidebar. What i do in reactjs is have a nested switch. And define my routes. Something like this:
<Switch>
<Route path="/pageOne">
<PageOne />
</Route>
<Route path="/pageTwo">
<pageTwo />
</Route>
</Switch>
but I have gone through a lot of resources, but non seems to talk about extending a page. Another option I am thinking of is to create a subfolder in the dashboard folder, then I will need to import the sidebar component on all the other pages, but this method breaks the DRY principle.
What is the better way to do this?
EDIT
This is what I am trying to archive. When I click the links in the sidebar, I navigate just the right side of the page, while the sidebar persists across the page.
if you're referring to the capacity to dynamically generate pages by appending a given value to some subpage "X" like the behavior that Switch provides, then you should check out the docs on dynamic router
Everything in Next is highly reusable, as it's extremely unopinionated about many things
If you want to dynamically generate subsubpages or subsubsubpages even off of some given pages subdirectory, then you can use the [dynamic].tsx filename and generate static paths using getStaticPaths followed with getStaticProps OR getServerSideProps (which does not use getStaticPaths). To clarify, Next's architecture, you are executing on both the server and the client in the same file when using a pages file (excluding pages/* and pages/api* routes). The pages/api routes are serverless node environments and can be fetched from the default export on the client of any non-pages/* pages/* file. getStaticProps still executes on the server and therefore contributes 0 to your bundle size. Same goes for getStaticPaths. You only need the latter when using getStaticProps within a dynamic file-type ([dynamic].tsx [...dynamic-catch-all].tsx, [[...dynamic-catch-all-optional]].tsx)
check out my profile for some repos with dynamic routing if you'd like
If I'm being honest I had to refresh myself on what the Switch wrapper achieves in CRApp because it's been so long since I've worked in it. I have been using Next with TSX for over a yr now so feel free to shoot any follow up ?s.
Here's an example from a recent client project which dynamically generates 25+ gallery subpages during build
components/Gallery/gallery.tsx
import Image, { ImageLoaderProps } from 'next/image';
import { Timestamp, Container } from '#/components/UI/index';
import { parseUrl } from '#/lib/helpers';
import Link from 'next/link';
import { Gallery } from '#/types/booksy/media';
export default function GalleryMapped({
images,
images_count,
images_per_page
}: Gallery) {
const GalleryImageLoader = ({
src,
width,
quality
}: ImageLoaderProps) => {
return `${src}?w=${width}&q=${quality || 75}`;
};
return (
<Container className='max-w-7xl mx-auto m-12 container'>
<ul
role='list'
className='grid grid-cols-1 gap-x-4 gap-y-8 sm:grid-cols-2 sm:gap-x-6 lg:grid-cols-3 max-w-7xl mx-auto'
>
<span className='sr-only'>{images_per_page}</span>
{images
.map((photo, i) => {
const targetedThumbnail = photo.thumbnails['640,0-hr'].url;
// console.log('target: ', targetedThumbnail);
const thumbnailDecoded = decodeURI(targetedThumbnail);
// console.log('decoded: ', thumbnailDecoded);
const fragmentThumbnailURI = parseUrl(thumbnailDecoded);
// console.log('URI Fragments: ', fragmentThumbnailURI);
const thumbnailReconstructed = `${fragmentThumbnailURI!.baseUrl.concat(
fragmentThumbnailURI!.pathname
)}`;
// console.log('reconstructed: ', thumbnailReconstructed);
return (
<li key={i++} className='relative'>
<div className='group cover block w-full rounded-xl bg-redditBG focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-offset-gray-100 focus-within:ring-indigo-500 overflow-hidden'>
<Link
href='/gallery/[id]'
as={`/gallery/${photo.image_id}`}
passHref
shallow={true}
scroll={true}
>
<a id={`/gallery#${photo.image_id}`}>
<Image
loader={GalleryImageLoader}
src={thumbnailReconstructed ?? photo.image}
width='1280'
height='1294'
alt={`${photo.description ?? photo.category}`}
quality={100}
className='object-cover pointer-events-none group-hover:opacity-75 shadow-cardHover'
/>
</a>
</Link>
<button
type='button'
className='absolute inset-0 focus:outline-none'
>
<span className='sr-only'>
View details for {photo.image_id}
</span>
</button>
</div>
<p className='mt-2 block text-sm font-medium text-olive-300 truncate pointer-events-none'>
<Timestamp timestamp={photo.created} />
</p>
<p className='block text-sm font-medium text-gray-500 pointer-events-none'>
{`${++i}/${images_count}`}
</p>
</li>
);
})
.reverse()}
</ul>
</Container>
);
}
Then, it's imported into the pages/gallery/[id].tsx where getStaticPaths and getStaticProps are injected with server-fed props of the current incoming data by apollo client and SWR.
pages/Gallery/[id].tsx
import {
GetStaticPropsContext,
GetStaticPropsResult,
GetStaticPathsContext,
InferGetStaticPropsType
} from 'next';
import { initializeApollo, addApolloState } from '#/lib/apollo';
import {
DynamicNavDocument,
DynamicNavQueryVariables,
DynamicNavQuery,
WordpressMenuNodeIdTypeEnum
} from '#/graphql/generated/graphql';
import { AppLayout } from '#/components/Layout';
import { useRouter } from 'next/router';
import { Container, Fallback } from '#/components/UI';
import useSWR from 'swr';
import { fetcherGallery } from '#/lib/swr-fetcher';
import { Gallery } from '#/types/booksy/media';
import { Configuration, Fetcher } from 'swr/dist/types';
import {
getLatestBooksyPhotos,
getBooksyPhotoById
} from '#/lib/booksy';
import Image, { ImageLoaderProps } from 'next/image';
import { parseUrl } from '#/lib/helpers';
export async function getStaticPaths({
locales
}: GetStaticPathsContext): Promise<{
paths: string[];
fallback: false;
}> {
const data: Response = await getLatestBooksyPhotos();
const pathsData: Gallery = await data.json();
return {
paths: locales
? locales.reduce<string[]>((arr, locale) => {
pathsData.images.forEach(imageId => {
arr.push(`/${locale}/gallery/${imageId.image_id}`);
});
return arr;
}, [])
: pathsData?.images.map(
imageId => `/gallery/${imageId.image_id}`
),
fallback: false
};
}
export async function getStaticProps<P>(
ctx: GetStaticPropsContext
): Promise<
GetStaticPropsResult<
P & {
Header: DynamicNavQuery['Header'];
Footer: DynamicNavQuery['Footer'];
initDataImage: Partial<
Configuration<Gallery, any, Fetcher<Gallery>>
>;
id: string;
}
>
> {
const apolloClient = initializeApollo({
headers: ctx.params ?? {}
});
await apolloClient.query<
DynamicNavQuery,
DynamicNavQueryVariables
>({
notifyOnNetworkStatusChange: true,
fetchPolicy: 'cache-first',
query: DynamicNavDocument,
variables: {
idHead: 'Header',
idTypeHead: WordpressMenuNodeIdTypeEnum.NAME,
idTypeFoot: WordpressMenuNodeIdTypeEnum.NAME,
idFoot: 'Footer'
}
});
const id = ctx?.params ? (ctx.params.id as string) : '21177790';
const initDataGallery = await getBooksyPhotoById(id);
const initDataImage: Gallery = await initDataGallery.json();
return addApolloState(apolloClient, {
props: {
initDataImage,
id
},
revalidate: 600
});
}
export default function GalleryById<
T extends typeof getStaticProps
>({
Header,
Footer,
initDataImage,
id
}: InferGetStaticPropsType<T>) {
const router = useRouter();
const parsedId = router.query
? (router.query.id as string)
: '';
const { data } = useSWR<Gallery>(
`/api/booksy-image-by-id/?category=biz_photo&image_id=${
id ? id : parsedId
}`,
fetcherGallery,
initDataImage
);
const booksyImageLoader = ({
src,
width,
quality
}: ImageLoaderProps) => {
return `${src}?w=${width}&q=${quality || 75}`;
};
const targetThumbnail = data?.images[0].thumbnails['640,0-hr']
.url
? data.images[0].thumbnails['640,0-hr'].url
: data?.images[0].image
? data.images[0].image
: '';
const thumbnailDecoded = decodeURI(targetThumbnail ?? '');
const fragmentThumbnailURI = parseUrl(thumbnailDecoded ?? '');
const thumbnailReconstructed =
`${fragmentThumbnailURI?.baseUrl.concat(
fragmentThumbnailURI.pathname
)}
` ?? '';
return (
<>
{router.isFallback ? (
<Fallback />
) : (
<AppLayout
Header={Header}
Footer={Footer}
title={`${data?.images[0].image_id ?? parsedId}`}
>
<Container
clean
className='my-16 max-w-5xl mx-auto block rounded-xl shadow-cardHover'
>
{data && data.images ? (
<Image
className='rounded-xl object-cover'
src={
thumbnailReconstructed !== ''
? thumbnailReconstructed
: '/doge-404.jpg'
}
loader={booksyImageLoader}
width='1280'
height='1294'
priority
quality={100}
layout='responsive'
/>
) : (
<Fallback />
)}
</Container>
</AppLayout>
)}
</>
);
}
The directory
and there are 48 paths being generated in production builds at the moment
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).