next/image not working with props as image source - reactjs

My Home page sends data from my strapi cms to my PostSlider component via props
import React from "react";
import styles from './index.module.scss'
import { AxiosService } from '../utils/axios-service'
import PostSlider from '../components/postSlider/postSlider'
const Home = ({ posts }) => {
return (
<div id='contentsWrap' className={styles.dohandsWrap}>
<PostSlider home={true} posts={posts} />
</div>
)
}
export default Home
export async function getStaticProps() {
const axios = AxiosService.create()
const res = await axios.get('/archives', {
params: {
category: 'news',
display: true,
showDoson: true,
_limit: 5,
_sort: 'id:DESC'
}
})
return {
props: {
posts: res.data,
},
}
}
My postSlider component then maps over the data to fill my slider
import React from "react";
import Slider from "react-slick";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
import styles from './postSlider.module.scss'
import Link from 'next/link'
import Image from 'next/image'
export default function PostSlider({ home, posts }) {
var settings = {
infinite: posts.length > 2 ? true : false,
autoplay: false,
speed: 500,
autoplaySpeed: 3000,
slidesToShow: 3,
slidesToScroll: 1,
};
return (
<section className={`${styles.postSlider} postSlider ${home ? styles.postSliderHome : 'postSliderNotHome'} ${posts.length > 2 ? 'postSliderPadding' : ''}`}>
<Slider {...settings}>
{posts.map((post) => {
const date = new Date(post.displayDate);
return (
<Link key={post.id} href={`/news/${post.id}`}>
<a className={styles.postSliderLink}>
<article>
<Image src={post.images[0]?.url} alt={post.images[0]?.alternativeText} width={376} height={190} layout="fixed" />
</article>
</a>
</Link>
)
})}
</Slider>
</section>
);
}
I made sure to include my cdn address in module.exports in next.config.js but I get the following error
Error: Image is missing required "src" property. Make sure you pass
"src" in props to the next/image component. Received:
{"width":376,"height":190}
If I remove the next/image component for the normal img tag, everything works fine.
What am I doing wrong?

Well, it seems like one of your posts have empty images array?
Image component is required to have src property and you pass undefined instead.
You can check if there is at least one image and then render it, like that:
<article>
{post.images.length > 0 && (
<Image src={post.images[0].url} alt={post.images[0].alternativeText} width={376} height={190} layout="fixed" />
)}
</article>

Try before the return:
const src = {src: post.images[0]?.url}
Then inside the return:
<Image {...src} //etc...

Sometimes, the <Image /> tag doesn't work like it should and doesn't accept the src . Try defining the URL before return and then pass the URL in the src property.
Just before return:
const url = post.images[0]?.url;
And then you can add:
<Image src={url} alt={post.images[0]?.alternativeText} width={376} height={190} layout="fixed" />

Related

I want to display Google Adsense on my gatsby.js site. However, it is not showing up

I want to display Google Adsense on my gatsby.js site. However, it is not showing up.
LeftSideSection is called in Layout.js.
I am running it in a local environment.
And I don't have a domain for my site.
I don't register my site's domain in GoogleAdsense and
I have created an Ad unit.
export
[
googleAdsense.js
import React from "react"
import * as styles from "./LeftSideSection.module.css";
import {Adsense} from './googleAdsense'
import React, { useEffect } from 'react'
export const Adsense = ({ path }) => {
useEffect(() => {
;(window.adsbygoogle = window.adsbygoogle || []).push({})
}, [path])
return (
<ins
className="adsbygoogle"
style={{ "display": "block" , textAlign: "center",width:`100%` ,height:`100%`}}
data-ad-client="ca-pub-xxxxxxxxx"
data-ad-slot="xxxxxxx"
data-ad-format="auto"
data-full-width-responsive="true"
data-adtest="on"
/>
)
}
LeftSideSection.js
const LeftSideSection = (props) => {
const { title, children } = props;
const path = props.location?.pathname || '';
return (
<section className={styles.container}>
<p>ads</p>
<Adsense path={path} />
</section>
);
};
export default LeftSideSection;
Layout.js
import React from "react";
import Header from "./Header";
import * as styles from "./Layout.module.css";
import 'bootstrap/dist/css/bootstrap.min.css';
import herderImage from '../images/header.png'
import {Navbar} from 'react-bootstrap'
import RightSideSection from "./RightSideSection";
import LeftSideSection from "./LeftSideSection";
import { Link } from "gatsby";
import { useBreakpoint } from 'gatsby-plugin-breakpoints';
import HeaderRss from "./HeaderRss";
const Layout = ({ children }) => {
const breakPoints = useBreakpoint();
return (
breakPoints.pc ?
<>
<Navbar.Brand as={Link} href='/' >
<img src={herderImage} style={{width:`100%`,height:`200px`,}}/>
</Navbar.Brand>
<Header />
<div className={styles.container}>
<div className={styles.LeftSideSection}>
<LeftSideSection />
</div>
<div className={styles.RightSideSection}>
<RightSideSection />
</div>
<div className={styles.mainPane}>
<div className={styles.headerRssContainer}>
<HeaderRss/>
</div>
{children}
</div>
</div>
<footer className={styles.footer}>
© {new Date().getFullYear()},
{`title`}
</footer>
</>:
);
};
export default Layout;
enter image description here
You are not loading the <script> that the console is suggesting. Try using the Helmet component to do something like:
import React from "react"
import * as styles from "./LeftSideSection.module.css";
import {Adsense} from './googleAdsense'
import React, { useEffect } from 'react'
export const Adsense = ({ path }) => {
useEffect(() => {
;(window.adsbygoogle = window.adsbygoogle || []).push({})
}, [path])
return <>
<Helmet>
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
</Helmet>
<ins
className="adsbygoogle"
style={{ "display": "block" , textAlign: "center",width:`100%` ,height:`100%`}}
data-ad-client="ca-pub-xxxxxxxxx"
data-ad-slot="xxxxxxx"
data-ad-format="auto"
data-adtest="on"
data-full-width-responsive="true"
/>
</>
}
I still don't know what's import {Adsense} from './googleAdsense', this line may collide with the naming of the component that you are defining (both are Adsense). If the issue persists, try changing the name.
To make the ads available on localhost, set the data-adtest as on.
In addition, you can try using a React-based solution like the one that react-adsense suggests.
Double-check and remove AdBlocks (or similar).
However, the image of the ad did not show up.
This can be caused by the localhost. Try deploying the site to check it in a real domain.

'Cannot Find Module' when using an Image in React

I am using React and I am running into an issue importing images in a component. Now I know how to use the import method, which is fine for some things but in this case the image src is part of an array of objects I need to map over.
So let me start with if I do this directly: <img src={require('../../images/leadinvestigator.jpg')} /> It works just fine.
However if I do this: <img src={require(member.image)} /> or <img src={require(${member.image})} /> I get:
react-dom.development.js:11340 Uncaught Error: Cannot find module '../../images/leadinvestigator.jpg'
and if I do this: <img src={require({member.image})} /> I get an invalid token error
here is my component code:
import React from "react"
import "react-responsive-carousel/lib/styles/carousel.min.css"
import { Carousel } from 'react-responsive-carousel'
import './styles.css'
const Crew = () => {
const crewMembers = [
{
image: '../../images/leadinvestigator.jpg',
name: 'Bryant Richards',
title: 'Lead Investigator',
quote: 'In the end, it only matters what you believe'
}
]
return (
<Carousel
showArrows={true}
infiniteLoop={true}
showThumbs={false}
showStatus={false}
autoPlay={true}
interval={6100}
>
{
crewMembers ? crewMembers.map(member => (
<div>
<img src={require('../../images/leadinvestigator.jpg')} />
<div className="myCarousel">
<h3>{member.name}</h3>
<h4>Designer</h4>
<p>
It's freeing to be able to catch up on customized news and not be
distracted by a social media element on the same site
</p>
</div>
</div>
)) : null
}
</Carousel>
)
}
export default Crew
Try to import your image before put it in the object.
Add on top of your component:
import bryantImage from '../../images/leadinvestigator.jpg'
and then add this image to your object like that:
const crewMembers = [
{
image: bryantImage,
name: 'Bryant Richards',
title: 'Lead Investigator',
quote: 'In the end, it only matters what you believe'
}
]

Do not show slider photos react With react-slick

I have the next .js project. I want to use react-slick.
I installed the react-slick and slick-carousel packages .
I added css carousel :
import React from "react";
import Slider from "react-slick";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
import image1 from '../../../assets/images/125.jpg'
import image2 from '../../../assets/images/Mina.jpg'
import image3 from '../../../assets/images/ffff.png'
const SliderPlugin=()=>{
return (
<>
<h2> Single Item</h2>
<Slider >
<div >
<img src={image1} alt="image1"/>
</div>
<div>
<img src={image2} alt="image2"/>
</div>
<div>
<img src={image3} alt="image2"/>
</div>
</Slider>
</>
)
}
export default SliderPlugin;
But no photo is displayed. Only in dev Tools, there are div and img.
Verify Image Path
Firstly, in order to verify Image path. Here I'll use the Network images for testeing its working fine.
import React, { Component } from "react";
import Slider from "react-slick";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
export default class SimpleSlider extends Component {
constructor(props) {
super(props);
this.state = {
images: [
"https://source.unsplash.com/1024x768/?nature",
"https://source.unsplash.com/1024x768/?water",
"https://source.unsplash.com/1024x768/?girl",
"https://source.unsplash.com/1024x768/?tree", // Network image
// require('./assets/images/abc.jpg'), // Local image
]
};
}
// other component code ...
render() {
const settings = {
dots: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1
};
return (
<div className="slider-wrapper">
<Slider {...settings}>
{this.state.images?.map((imageName, index) => <div key={`${index}`}>
<img src={imageName} alt={`${index}`} />
</div>)}
</Slider>
</div>
);
}
}

React-responsive-carousel (nextJS/strapi) images are not showing on mobile

I am working on a nextJS/Strapi online store and I want to use the react-responsive-carousel I followed all the steps on [ https://www.npmjs.com/package/react-responsive-carousel ].
(I am working on localhost)
The Carousel works fine on the desktop using the dynamic images from Strapi API (Single type collection) but the images don't show on my phone when I try to access the localhost from there. All other images from Strapi work just fine except the ones inside the Carousel.
Carousel code:
import { imgToUrl } from "../../utils/urls";
import { Carousel } from "react-responsive-carousel";
const index = ({ data }) => {
const images = data.slider.map((slide) => imgToUrl(slide.image)); //imgToUrl is a function that takes the image URL and concatinate it with HTTP://localhost:1337/
return (
<>
<Carousel
autoPlay={true}
emulateTouch={true}
infiniteLoop={true}
showThumbs={false}
width="100%"
>
{images.map((image) => (
<div className="h-full w-full">
<img className="w-full h-full" src={image} />
{/* <p className="legend">Legend 1</p> */}
</div>
))}
</Carousel>
</>
);
};
export default index;
imgToUrl Code:
export const API_URL =
process.env.NEXT_PUBLIC_API_URL || "http://localhost:1337";
/**
*
* #param {any} image
*
*/
export const imgToUrl = (image) => {
if (!image) {
return "/Products/3.jpg"; //default image when there is not image uploaded
}
if (image.url.indexOf("/") === 0) {
return `${API_URL}${image.url}`; // Concatinates http://localhost:1337 with the image url
}
return image.url;
};
Output of imToUrl :
http://localhost:1337/uploads/banner_3_d93516ad90.jpg
I would appreciate any help.
Thank you.
I am also using Strapi "headless" CMS as my backend and GraphQL API to retrieve data from frontend, and below is how I have currently implemented my "Strapi Media" Image component:
frontend/utils/media.js
export function getStrapiMedia(url) {
if (url == null) {
return null
}
// Return the full URL if the media is hosted on an external provider
if (url.startsWith("http") || url.startsWith("//")) {
return url
}
// Otherwise prepend the URL path with the Strapi URL
return `${
process.env.NEXT_PUBLIC_STRAPI_API_URL || "http://localhost:1337"
}${url}`
}
frontend/utils/types.js
import PropTypes from 'prop-types'
export const linkPropTypes = PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
url: PropTypes.string.isRequired,
text: PropTypes.string.isRequired,
newTab: PropTypes.bool,
})
export const mediaPropTypes = PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
alternativeText: PropTypes.string,
mime: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
})
export const buttonLinkPropTypes = PropTypes.shape({
theme: PropTypes.string,
text: PropTypes.string.isRequired,
newTab: PropTypes.bool,
})
frontend/components/elements/image.js
import { getStrapiMedia } from "utils/media"
import Image from "next/image"
import PropTypes from "prop-types"
import { mediaPropTypes } from "utils/types"
const NextImage = ({ media, ...props }) => {
const { url, alternativeText } = media
const loader = ({ src }) => {
return getStrapiMedia(src)
}
// The image has a fixed width and height
if (props.width && props.height) {
return (
<Image loader={loader} src={url} alt={alternativeText || ""} {...props} />
)
}
// The image is responsive
return (
<Image
loader={loader}
layout="responsive"
width={media.width}
height={media.height}
objectFit="contain"
src={url}
alt={alternativeText || ""}
/>
)
}
Image.propTypes = {
media: mediaPropTypes.isRequired,
className: PropTypes.string,
}
export default NextImage
And below is an example use case from another component's context:
...
import NextImage from "./image"
...
<div className="flex flex-row items-center">
<Link href="/">
<a className="h-8 w-32">
<NextImage layout="fill" className="image" media={navbar.logo} />
</a>
</Link>
</div>
...
I hope this helps - let me know if you could use further source share here.
I am just learning the Strapi Framework myself, opting to bootstrap my software engineering portfolio, profile, and blog site from Strapi Next Corporate Starter. Are you also using a Strapi bootstrapped project, or custom using their SDK?
While working on my own custom Carousel I also discovered that if you are implementing your custom component as a section component, you will need to add the import statement and array member to the Strapi defaults in:
frontend/components/sections.js
Example from my use case:
...
import CardCarouselGroup from "#/components/sections/card-carousel-group";
...
// Map Strapi sections to section components
const sectionComponents = {
"sections.hero": Hero,
"sections.large-video": LargeVideo,
"sections.feature-columns-group": FeatureColumnsGroup,
...
"sections.card-carousel-group": CardCarouselGroup
}
...

How do you write a conditional to ignore a null value for an image in gatsby?

Strapi has an option to make an image required or not, but regardless of whether you select the required button, it makes it required and renders a null value in gatsby. How can I programmatically tell gatsby to render just the rich text if that is selected and ignore the null image value if not picture is uploaded? I wanted to do something like {image && ()}, but not sure how to map that..
import React from "react"
import { graphql } from "gatsby"
import ReactMarkdown from "react-markdown"
import Image from "gatsby-image"
//import Layout from "../components/layout"
const ComponentName = ({ data }) => {
const { title, layout } = data.strapiBasics;
return (
<div>
<h1>{title}</h1>
{layout.map(item => {
return (
<span key={item.id}><ReactMarkdown source={item.rich_text} />
<Image fluid={item.image.childImageSharp.fluid} />
</span>
)
})}
</div>
)
}
export const query = graphql`
query BasicQuery($slug: String!) {
strapiBasics(Slug: {eq: $slug}) {
title: Title
slug: Slug
layout: Layout {
id
rich_text
image: Image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`
export default ComponentName
Something like this should do the trick:
return (
<div>
<h1>{title}</h1>
{layout.map(item => {
return (
<span key={item.id}><ReactMarkdown source={item.rich_text} />
{item.image && <Image fluid={item.image.childImageSharp.fluid} />}
</span>
)
})}
</div>
);
Note: you may need to change the item.Image to check if it meets the condition.
Since you are aliasing your GraphQL query:
image: Image {...}
Your object will Image, not image, and so on with the rest.
You don't need to add the && logical operator inside, you just can return an image if it exists or return a markdown if don't.

Resources