Caching in Gatsby JS - reactjs

I have this Gatsby app where when I visit home page everything loads at first including the Testimonials section. However, when I visit another page, for instance the Blog list page and then click on the link back to homepage the data on Testimonials component won't load and you will see a blank area of the app where the Testimonials section is placed. In order to see the Testimonials list, you will have the refresh the page again.
For the record the data on my Testimonials component are being pulled out on Strapi JS that is deployed on Heroku.
So far I got this on my index.js:
import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/Layout"
import Header from "../components/Header"
import Testimonials from '../components/Testimonials'
import Blogs from '../components/Blogs'
import SEO from '../components/SEO'
export default function Home({ data }) {
const {
allStrapiBlogs: { nodes:blogs },
} = data
return (
<>
<SEO />
<div className="main-container">
<Layout>
<Header />
<Testimonials title="Testimonials" />
<Blogs title="Latest Blogs" blogs={blogs} showAllBlogLinks/>
<Map />
</Layout>
</div>
</>
)
}
export const query = graphql`
{
allStrapiBlogs(filter: {featured: {eq: true}}, sort: {fields: published_date, order: DESC}, limit: 6) {
nodes {
id
title
content
slug
published_date(formatString: "MMMM DD, YYYY")
featured_image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`
And then on my Testimonials.js component:
import React from "react"
import { graphql, useStaticQuery } from "gatsby"
import Image from "gatsby-image"
import { FaStar } from "react-icons/fa"
import Title from './Title'
const query = graphql`
{
allStrapiTestimonials {
nodes {
id
name
cite
text
photo {
childImageSharp {
fluid{
...GatsbyImageSharpFluid_withWebp
}
}
}
}
}
}
`
const Testimonials = ({ title }) => {
const data = useStaticQuery(query)
const { allStrapiTestimonials: { nodes:testimonials } } = data
return (
<div className="testimonial-section section-padding" id="testimonial" data-aos="zoom-in">
<div className="container">
<div className="row">
<div className="col-lg-12">
<div className="section-title-two center">
<Title title={title} />
</div>
</div>
</div>
<div className="testimonial-wrap row">
<div className="testimonial-slider owl-carousel">
{ testimonials.map(item => {
const { id, name, cite, text, photo } = item
return(
<div className="col-xl-8 col-lg-10 col-12 ml-auto mr-auto" key={id}>
<div className="testimonial-item mt-40">
<div className="testimonial_img">
<Image fluid={photo.childImageSharp.fluid} alt={name} style={{ position: "absolute", overflow: "visible", display: "block", width: "211px", height: "207px" }} />
</div>
<div className="testimonial_content xs-mt-40">
<div className="testimonial_content_item mb-30">
<div className="testimonial_content__pro">
<h4 className="mb-10">{ name }</h4>
<p>{ cite }</p>
</div>
<ul className="d-none d-sm-inline-block">
<li><FaStar></FaStar></li>
<li><FaStar></FaStar></li>
<li><FaStar></FaStar></li>
<li><FaStar></FaStar></li>
<li><FaStar></FaStar></li>
</ul>
</div>
<div>
<p>{ text } </p>
</div>
</div>
</div>
</div>
)
})}
</div>
</div>
</div>
</div>
)
}
export default Testimonials
Any idea what's causing this error? How can I fix it?

I've faced a similar issue a few months ago and the fix depends strictly on the implementation and your code. Basically, what is happening is that React's doesn't understand that he needs to rehydrate some components because pointing to some global objects as window or document of the DOM, outside the React's ecosystem (without using states) may block that rehydration, in your cause, because of jQuery.
All the possible solutions that bypass this issue will be patches (like trying to add the cache). The ideal solution would avoid using jQuery, which points directly to the DOM, with React, which manipulates the virtual DOM (vDOM).
There's nothing wrong with the code you've shared, however, based on some other questions that you did, you are using jQuery and using the window object, which prevents the rehydration of some React components. You should get rid of jQuery or using some React-based approach. Something like this should do the trick to force a loader across the whole site:
const Layout = ({ children }) => {
const [loader, setLoader]=useState(true);
useEffect(()=>{
setTimeout(()=> {
setLoader(false)
}, 400)
}, [])
return <section className={`site__wrapper`}>
<Header />
<main>{loader ? <Preloader/> : children}</main>
</section>;
};

Related

Error when trying to render data conditionally in React

I am querying data from a CMS via Graphql into my Gatsby project.
Sadly I was not thinking ahead and the content types text field wasn't set to required or given a default value, so now the value of this text field is for some elements null.
I tried avoiding this giving me issues by rendering the elements through a conditional statement checking if the element is empty or not.
This is my entire file:
import React from 'react'
import { graphql, Link } from 'gatsby'
import { GatsbyImage, getImage } from "gatsby-plugin-image"
import Layout from '../components/Layout'
import { MDXProvider } from "#mdx-js/react"
import MDXRenderer from "gatsby-plugin-mdx/mdx-renderer"
export default function MalreiTemplate({ data }) {
const picture = data.allContentfulMalerei.nodes
return (
<Layout>
{picture.map(pic => {
const image = getImage(pic.image)
return(
<div key={pic.slug} className="mb-3">
<div className="pt-3 d-flex justify-content-between">
<span><Link to="/malerei" style={{textDecoration: "none", color: "#589AAD"}}>← zurück</Link></span>
</div>
<hr />
<div className="artwork-detail-container d-flex">
<div className="artwork-detail-image-container">
<GatsbyImage image={image}/>
</div>
<div className="artwork-detail-text">
<h3>{pic.title}, {pic.year}</h3>
<h4>{pic.type}</h4>
<p className="pt-4">
<MDXProvider>
<MDXRenderer>
{pic.description !== null ? <p>{pic.description}</p> : <p>.</p>}
</MDXRenderer>
</MDXProvider>
</p>
</div>
</div>
<hr/>
</div>
)})}
</Layout>
)
}
export const query = graphql`
query($slug: String!) {
allContentfulMalerei(filter: { slug: { eq: $slug } }) {
nodes {
year
width
title
description {
childMdx {
body
}
}
image {
gatsbyImageData(width: 600, placeholder: BLURRED)
}
}
}
}
`
This is the relevant part:
<MDXProvider>
<MDXRenderer>
{pic.description ? pic.description.childMdx.body : <p>.</p>}
</MDXRenderer>
</MDXProvider>
I am getting this error message in return when I visit pages for those elements that have no text field. On all other sites I can see the content with no error.
Would someone have an idea on how to fix this? Thanks in advance.
Personally I would replace:
<p className="pt-4">
<MDXProvider>
<MDXRenderer>
{pic.description ? <p>{pic.description.childMdx.body}</p> : <p>.</p>}
</MDXRenderer>
</MDXProvider>
</p>
with:
{ picDescription ? (<p className="pt-4">{pic.description}</p>) : null }
because I don't see what value the MDX components are adding there and I suspect that error is coming from MDX (but I don't know for sure).

Working with images local files in Gatsby.js

I am trying to render a headshot for each artist displayed on the page. The artist data comes from a Json file, and the images are located in images/artists/headshots. I am using the regular img tag, but for some reason nothing is displaying on the page. Any help any one can give would be greatly appreciated.
import React from 'react'
import PropTypes from 'prop-types'
import { StaticImage } from 'gatsby-plugin-image'
import { useStyles } from './styles'
const ArtistsPage = ({ data }) => {
const classes = useStyles()
return (
<section>
<article className={classes.artistsBackground}>
<div className={classes.heroLayoutContainer}>
<h3 className={classes.title}>MEET THE ARTISTS</h3>
<StaticImage
className={classes.heroImage}
src='../../images/artists/hero-images/hero-image-artists.jpg'
alt='hero-image-artists'
placeholder='blurred'
/>
</div>
</article>
<article className={classes.artistsContainer}>
<div className={classes.flexContainer}>
{data.allArtistsJson.edges
.map(({ node }, idx) => {
const artist = `${node.firstName}+${node.lastName}`
.split('+')
.join(' ')
return (
<div className={classes.flexItem} key={idx}>
<div>
<img
src={`../../images/artists/headshots/${artist} Headshot.jpg`}
alt='artist-headshot'
/>
</div>
<div className={classes.artistCardName}>
{`${node.firstName} ${node.lastName}`.toUpperCase()}
</div>
<div className={classes.artistCardText}>{node.city}</div>
<div className={classes.artistCardText}>
{node.currentTeam}
</div>
</div>
)
})}
</div>
</article>
</section>
)
}
export default ArtistsPage
My image files are set up as:
FirstName LastName Headshots.jpg
I think your issue may comes from the white spaces in the naming. Your code looks good at first sight so try renaming your images with underscore or in camelCase:
<img
src={`../../images/artists/headshots/${artist}_Headshot.jpg`}
alt='artist-headshot'
/>
After much research and the nice people on Gatsby discord I found the answer to be… in a scenario like this I needed to add require().default.
Ex:
<img
src={require(../../images/artists/headshots/${artist} Headshot.jpg).default}
alt='artist-headshot'
/>

looping json data in Class Component

This is my index.js where I try to refer SampleApp
import React, { Component } from "react";
import { render } from "react-dom";
import './index.css';
import "../node_modules/bootstrap/dist/css/bootstrap.min.css";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
Redirect
} from "react-router-dom";
import SampleApp from "./pages/SampleApp";
import 'bootstrap/dist/css/bootstrap.min.css';
class App extends Component {
constructor() {
super();
this.state = {
name: "React",
isUserAuthenticated: true
};
}
render() {
return (
<Router>
<Switch>
<Route
exact
path="/"
render={() => {
return (
<Redirect to="/SampleApp" />
)
}}
/>
<Route exact path="/SampleApp" component={SampleApp} />
</Switch>
</Router>
);
}
}
render(<App />, document.getElementById("root"));
This is my SampleApp.js file. here I'm importing the Cards component from Cards.jsx
import React from 'react';
import '../../src/App.css';
import Cards from '../cards/cards';
const SampleApp = props => (
<React.Fragment>
<div className="App">
<div>
<div className="header">
<div className="header_fonts">
Sample Application
</div>
</div>
<div>
<div className="content_header_fonts">
This is sample app
</div>
<div className="content_fonts">
Sample app to deomntrate ideas.
</div>
<Cards></Cards>
</div>
</div>
</div>
</React.Fragment>
)
export default SampleApp;
this is my Cards.jsx file.
here I'm importing Card component and json data
import React, { Component } from "react";
import Card from './cardUI';
import CardData from '../source/data.json';
class Cards extends Component {
render() {
return
(
<div className="container-fluid d-flex justify-content-center">
<div className="row">
{
CardData.map((
{title, desc, icon, intro,developer_guide,api_ref }, id) =>
(
<div className="col-md-4">
<Card
title={title}
desc={desc}
intro={intro}
developer_guide={developer_guide}
api_ref={api_ref}/>
</div>
))
}
</div>
</div>
);
}
}
export default Cards;
this is a sample of my JSON file
[
{
"id" : 7,
"title" : "Melon Munchee",
"icon" : "https://cdn.onlinewebfonts.com/svg/img_393496.png",
"desc" : "If you are an Avatar fan, then this api is for you. Here you can find everything from Episodes to Characters.",
"intro": "intro_7",
"developer_guide": "d_link7",
"api_ref": "api_link7"
},
{
"id" : 8,
"title" : "Browns Barns",
"icon" : "https://cdn.onlinewebfonts.com/svg/img_386567.png",
"desc" : "Baseball fans? Computer nerds? Now, in one place, you have baseball data and an api to access it. Have fun!.",
"intro": "intro_8",
"developer_guide": "d_link8",
"api_ref": "api_link8"
}
]
Card.jsx file
This is how implemented the Card component
import React from 'react';
import "../../node_modules/bootstrap/dist/css/bootstrap.min.css";
import * as Icon from '../../node_modules/react-bootstrap-icons';
import './card-style.css';
const Card = props =>{
return(
<div className="card text-center">
<div className="card-body text-dark">
<Icon.Alarm></Icon.Alarm>
<h4 className="card-title">
{props.title}
</h4>
<p className="card-text text-secondary">
{props.desc}
</p>
<ul class="list-group">
<li class="list-group-item">{props.intro}</li>
<li class="list-group-item">{props.developer_guide}</li>
<li class="list-group-item">{props.api_ref}</li>
</ul>
</div>
</div>
)
}
export default Card;
but I'm getting an error as following
Error: Cards(...): Nothing was returned from render. This usually
means a return statement is missing. Or, to render nothing, return null.
19 stack frames were collapsed. Module.
src/index.js:44 41 | } 42 | } 43 |
44 | render(, document.getElementById("root"));
I am actually going to take a guess here and say that your specific error is caused by the new line after your return statement. So remove it to make it look like this return ( and it should work... or at least that error should go away.
Check out this sandbox: https://codesandbox.io/s/xenodochial-fog-y8pk2?file=/src/App.js
just go ahead and add a new line after the return and see your exact error.
It's just a typo mistake. When you use line terminator next to the return statement, JS adds semicolon automatically and that will be the end of function execution and returns undefined. That's why your Cards component is not able to find the JSX because Cards render returns undefined.
As per MDN docs.
The return statement is affected by automatic semicolon insertion (ASI). No line terminator is allowed between the return keyword and the expression.
To fix this, update Cards render function with this
class Cards extends Component {
render() {
return ( // was the issue earlier
<div className="container-fluid d-flex justify-content-center">
<div className="row">
{
CardData.map(({ title, desc, icon, intro,developer_guide,api_ref }, index) => (
<div className="col-md-4" key={title + index}>
<Card
title={title}
desc={desc}
intro={intro}
developer_guide={developer_guide}
api_ref={api_ref} />
</div>
)
)
}
</div>
</div>
);
}
}

Best way to implement image enlargement on Thumbnails on Product Pages in Gatsby

List item
My product thumbnails don't enlarge on click using gatsby-remark-images-medium-zoom#1.2.1 or gatsby-remark-images-zoom
Followed readme on both and declared plugins in gatsby-config, also tried experimenting with option configurations. To see what I mean here's an example: https://store.shaka-surf.com/products/eco-medium-g5-surf-fins
import React from 'react'
import Img from 'gatsby-image'
import { graphql, useStaticQuery } from 'gatsby'
export default function Thumbnails({ src }) {
const { allMoltinProduct } = useStaticQuery(graphql`
query allMoltinProductsQuery {
allMoltinProduct {
nodes {
id
images {
childImageSharp {
sizes(sizes: "max-width: 801px) 100vw, 801px") {
srcSet
sizes
}
}
}
}
}
}
`)
return (
<div className="thumbnail-container">
{allMoltinProduct.nodes.map(product => (
<React.Fragment key={product.id}>
{product.images.map((image, index) => (
<ul className="thumbnail-list">
<li key={`image-${index}`} style={{display: 'inline-block', float:
'none', color: '#F2F4F5', width: '44px', height: '44px'}}>
<Img fluid={image.childImageSharp.fluid.src}
/>
<img sizes={image.childImageSharp.sizes.sizes} src=
{image.childImageSharp.fluid.src} srcSet=
{image.childImageSharp.sizes.srcSet} className="thumbnail-image medium-zoom- image" loading="lazy" alt={product.name} />
>
</li>
</ul>
))}
</React.Fragment>
))}
</div>
)
}
Would like the product thumbnails to enlarge.
UPDATE: managed to get Lightbox from this repo working on my gallery which is good enough for now. Will come back to the thumbnails at a later date.

React-reveal Image Slide

I am using react reveal and doing an image slide up transition but the image is not showing, I have given the code below as well as the output image. I have added a picture which shows whats happening. the link in the picture was supposed to be an image but it's showing just Link
import React from 'react';
import { Link } from 'react-router-dom';
import Reveal from 'react-reveal';
import 'animate.css/animate.css';
const generateBlocks = ({blocks}) =>{
if(blocks){
return blocks.map((item)=>{
const styles = {
background:`url('/images/blocks/${item.image}') no-repeat `
}
return(
<Reveal key={item.id} effect="animated fadeInUp"
className={`item ${item.type}`}>
<div className="veil"></div>
<div
className="image"
style={styles} >
</div>
<div className="title">
<Link to={item.link}>{item.title}</Link>
</div>
</Reveal>
)
})
}
}
const Blocks = (props) =>{
return(
<div className ="home_blocks">
{generateBlocks(props)}
</div>
)
}
export default Blocks;][1]
Heve you tried to import the right component from Reveal:
import Reveal from 'react-reveal/Reveal';
Have a look into the Documentation: https://www.react-reveal.com/examples/common/custom/

Resources