No image uploaded "SRC" is undefined even with a check? - javascript

I'm facing a weird problem here I've created a check whether an image is uploaded or not. But for some reason, my "else" is not working.
Inside my main component "Fragrances" I'm looping through my API. And checking if the Array of images is empty return else show the image.
What am I doing wrong?
My code:
image component:
import React from 'react';
import NoPicture from 'components/NoPicture/NoPicture';
const Image = props => {
const { url } = props;
return url.length > 0 ? <img src={url} className="image" /> : <NoPicture />;
};
export default Image;
NoPicture component:
import React from 'react';
// No Picture
import NoPhotoImageURL from '../../images/no-photo.svg';
console.log(NoPhotoImageURL);
const NoPicture = () => (
<img
src={NoPhotoImageURL}
alt="No Photo"
className="image image--default"
/>
);
export default NoPicture;
Main component:
import React from 'react';
import { SITE_URL } from 'constants/import';
import Name from './name';
import Category from './category';
import Image from './image';
import Gallery from 'components/Gallery/gallery';
import Rating from './rating';
import Description from './description';
import Notes from './notes';
const Fragrances = props => {
const { FragranceData } = props;
return (
<section className="fragrances">
<div className="row">
{FragranceData.map(fragrance => {
console.log(fragrance);
const {
category,
description,
image,
gallery,
name,
rating,
notes,
Publish: isPublished,
} = fragrance;
const imageURL = image.path;
return isPublished ? (
<div key={fragrance._id} className="col-xs-12 col-sm-6">
<div className="fragrance">
<Name name={name} />
<Category category={category} />
<Image url={SITE_URL + imageURL} />
<Rating rating={rating} />
<Description description={description} />
<Notes notes={notes} />
<Gallery imageData={gallery} />
</div>
</div>
) : (
'Nothing published yet!'
);
})}
</div>
</section>
);
};
export default Fragrances;

Your question is not entirely clear on what exactly you are experiencing, but here is the most obvious problem in your code. You have this line in your Image component:
return url.length > 0 ? <img src={url} className="image" /> : <NoPicture />;
However, in your main component you are passing a concatenated string to the Image component:
<Image url={SITE_URL + imageURL} />
According to your comment, SITE_URL is the full URL, which will never be empty, so inside your Image component, url will always contain something, no matter what the value of imageURL is in the main component. Thus, url.length will always be greater than 0, and the img tag will render every time.
You will either need to pass the individual parts of the path down to the Image component separately, or move your check up into the main component.

Related

How to access the state of a component at a superior level without using useContext?

let me explain my question.
I would like to create expanding flex cards, here is the exemple on codepen : https://codepen.io/z-/pen/OBPJKK
and here is my code for each button :
basically I have a component which is called HomeButtons that generates every flex cards. Inside this component I have a smaller component called readMore. In this component I have a useState that allows me to toggle individually each button to add or retreive an active class. If the active class is present, that means that the selected button must expand and the other ones must shrink.
What I would like to do is to access the readMore state ouside of the readMore subcomponent. That way I could write a function to remove the active class from a card if the user clicks on another card like so :
function setToUnactive() {
if (readMore(true)) {
readMore(false)}
}
My question is how can I get the state of readMore outside of the readMore subcomponent ? Do I need to use useContext ? Because that seems very simple to do but I tried a lot of things and nothing works. Can I pass the state readMore as a prop of the component ReadMore ? Thank you !
import React, { useState } from 'react';
import '../style/catalogue.scss';
import collectionsItems from '../Components/collectionsItemsData';
import { Link } from "react-router-dom";
const HomeButtons = ({}) => {
function ReadMore() {
const [readMore, setReadMore] = useState(false)
function toggleSetReadMore() {
setReadMore(!readMore)
}
return (
<p className='showmore' onClick={toggleSetReadMore} className={readMore ? "collection-item active" : "collection-item"}>TOGGLE BUTTON</p>
)
}
return <div>
{collectionsItems.map((collectionItem) => {
const { id, category, img } = collectionItem;
return < article key={id} >
<img className="item-img" src={img} alt=''/>
<ReadMore />
<Link to={`/${category}`} className="item-title">{category}</Link>
</article>
})}
</div>
}
export default HomeButtons;
First of all you need extract ReadMore component from function outside!
And for your problem you can lift state up(https://reactjs.org/docs/lifting-state-up.html). And since at the same time only one item can be opened you can do something like this:
function ReadMore({ isOpened, setOpened }) {
return (
<p
onClick={setOpened}
className={isOpened ? "collection-item active" : "collection-item"}
>
TOGGLE BUTTON
</p>
);
}
const HomeButtons = () => {
const [openedItemId, setOpenedItemId] = useState(null);
return (
<div>
{collectionsItems.map((collectionItem) => {
const { id, category, img } = collectionItem;
return (
<article key={id}>
<img className="item-img" src={img} alt="" />
<ReadMore
isOpened={openedItemId === id}
setOpened={() => setOpenedItemId(id)}
/>
<Link to={`/${category}`} className="item-title">
{category}
</Link>
</article>
);
})}
</div>
);
};

Next.js Image component error src missing

I have the following error occurring when I attempt to use the next.js image component.
Error: Image is missing required "src" property. Make sure you pass "src" in props to the `next/image` component. Received: {}
The src value being passed in is:
https://res.cloudinary.com/mward82/images/q_auto:eco/v1616884491/1E3EDA11-D657-4FBD-8123-EFE0C5F43AC8_idzuc7/1E3EDA11-D657-4FBD-8123-EFE0C5F43AC8_idzuc7.webp
I can confirm this when I use img instead of Image.
The following is the code in question, from components/cover-image.js
import cn from "classnames";
import Link from "next/link";
import Image from "next/image";
export default function CoverImage({ title, coverImage, slug }) {
const image = (
<Image
src={coverImage?.sourceUrl}
height={coverImage?.mediaDetails.height}
width={coverImage?.mediaDetails.width}
className={cn("shadow-small", {
"hover:shadow-medium transition-shadow duration-200": slug
})}
/>
);
console.log(coverImage);
return (
<div className="sm:mx-0">
{slug ? (
<Link as={`/posts/${slug}`} href="/posts/[slug]">
<a aria-label={title}>{image}</a>
</Link>
) : (
image
)}
</div>
);
}
My next.config.js files contains the following:
module.exports = {
images: {
domains: ["res.cloudinary.com"]
}
};
You can see a forked copy of my sandbox
https://codesandbox.io/s/script-hungryvercelapp-forked-7wd9e
The problem was that my page was listing posts that don’t contain images. Modifying the code in components/cover-image.js to check for the existence of coverImage solved the problem.
The two references to image in the return section were changed to coverImage && image so that the image component rendered conditionality based on the existence of coverImage.
This is the working components/cover-image.js:
import cn from "classnames";
import Link from "next/link";
import Image from "next/image";
export default function CoverImage({ title, coverImage, slug }) {
const image = (
<Image
src={coverImage?.sourceUrl}
height={coverImage?.mediaDetails.height}
width={coverImage?.mediaDetails.width}
className={cn("shadow-small", {
"hover:shadow-medium transition-shadow duration-200": slug
})}
/>
);
console.log(coverImage);
return (
<div className="sm:mx-0">
{slug ? (
<Link as={`/posts/${slug}`} href="/posts/[slug]">
<a aria-label={title}>{coverImage && image}</a>
</Link>
) : (
coverImage && image
)}
</div>
);
}
Thanks to Yash Sangai for pushing me in the correct direction.

Display Multiple Images from Json in ReactJS

I've managed to create a mockup json that i need to test a json request via axios on a react app.
For now, i can console.log the json file structure and can assign the data for the link.
The problem is that my content it's not being rendered correctly in the DOM via Map Method. the images are not appearing.
import {Link} from 'react-router-dom';
import axios from 'axios';
class DesignItem extends Component {
state = {
isLoading: true,
designs: [],
error: null
}
componentDidMount () {
axios.get('http://www.mocky.io/v2/5dadd81c2d0000e0f5e4bd57')
.then (res => {
console.log(res.data);
const designs = res.data;
this.setState({designs})
})
}
render() {
return (
<React.Fragment>
{this.state.designs.map(designs => (
// this one is appearing right as expected
<Link to={designs.productPage}>
<div className="design-item" key={designs.id}>
// this image doesn't appear. the URL is there but the image it's broken
<img src={designs.featUrl} alt="" />
</div></Link>
))}
</React.Fragment>
);
}
}
export default DesignItem;```
<React.Fragment>
{this.state.designs.map(designs => (
<Link to={designs.productPage} key={designs.id}> // I think the key must be put here instead on the div
<div className="design-item">
<img src={designs.featUrl} alt="" />
</div>
</Link>
))}
</React.Fragment>
Also upon checking the data, the image source was like this:
../images/products/alexandre-iii/0.jpg
Maybe that is why it is not showing up, if you could change the url to something like:
https://your-domain.com/public/images/products/alexandre-iii/0.jpg
It will show up.

How Can I use the returned string (new feature of React v16.0.0) in the source tag of an image ex: <img src='returnedString' />?

I want to use the new feature on React v16.0.0 for returning a string, then use that string in
<img src="returnedString" >
What is the current behavior?
Well if I render my component in a
<div > <MyComponent /> </div>
I can see the string displayed on the screen (see attached screenshot), but my goal is to use that string in <img src="returnedString" />
here is my code:
// My component that returns strings
class MyComponent extends Component {
render(){
switch (this.props.type) {
case 'text':
return this.props.json.data[this.props.Key]
break
case 'image':
return this.props.json.data[this.props.Key]
break
default:
return null
break
}
}
}
const UserComponent = (props) => {
return (
<div>
{/* this displays the string on the page */}
<MyComponent type='image' Key='avatar' desc='Abified image' {...props} />
{/* If I console.log this line I get <img src={[object object]} /> */}
<img src={<MyComponent type='image' Key='avatar' desc='Abified image' {...props} />} />
</div>
)
}
// Parent Component
class App extends Component {
constructor(props){
super(props)
this.state = {
json:[]
}
}
// Fetching data from an api
componentDidMount(){
fetch("https://reqres.in/api/users/2")
.then(response => response.json())
.then(json => {
this.setState({json: json })
})
}
render() {
return (
<div>
<UserComponent {...this.state}/>
</div>
);
}
}
export default App;
How Can I achieve that?
What is the expected behavior?
I want to use the returned string inside an
Which versions of React ?
React v16.0.0
Did this work in previous versions of React?
No because it's a new feature in React v16.0.0
If you want to set the image's src attribute dynamically, then use a plain javascript function instead of a component:
const getImageSrc = props => {
switch (props.type) {
case 'text':
case 'image':
return props.json.data[props.Key]
}
}
Then you can call it from your component's render method like this:
<img src={ getImageSrc({...this.props, type: 'image', Key: 'avatar'}) } />
Because this
<MyComponent type='image' Key='avatar' desc='Abified image' />
is creating a text node in the dom.
But in this case
<img src={<MyComponent type='image' Key='avatar' desc='Abified image' {...props} />
your src attribute is getting a react element object.
You'll never get a string like that.
If you want to get your src dynamically, try something like this
const UserComponent = (props) => {
// calculate you src here
const imageSrc = props.json.data['avatar'];
return (
<div>
<img src={ imageSrc } />
</div>
)
}
Hope this helps.

React-bootstrap styling showing up before finished api call

I am making a small application in React that fetches a random image using Axios. I am using React-bootstrap to style the image, however a small white box is displayed for half of a second before the image is done loading. How can I resolve this?
This is my code:
import React, { Component } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
import { Image, Button } from 'react-bootstrap';
const ROOT_URL = 'myurl'
export default class WhatDog extends Component {
constructor(props){
super(props);
this.state = { randomImg: '' };
}
componentDidMount(){
axios.get(ROOT_URL)
.then(res => {
const data = res.data.message
this.setState({ randomImg: data })
})
}
renderImage(){
return(
<div>
<Image src={this.state.randomImg} className="img" thumbnail/>
<Link to="/">
<Button bsStyle="danger" bsSize="large">Go back</Button>
</Link>
</div>
)
}
render() {
return (
<div className="App">
{
(this.state.randomImg === '')
? <div>
<h1>Loading...</h1>
</div>
: <div>
{this.renderImage()}
</div>
}
</div>
);
}
}
The browser will fire the onLoad event, after the image has been, you name it.. loaded so before that, set the visibility to hidden.. NOT display: none ! Because display: none will also prevent the loading.
The solution might look something like this
<Image
src={this.state.randomImg}
style={!this.state.imgVisible ? {visibility: 'hidden'} : {}}
onLoad={() => this.setState({ imgVisible: true })}
/>
Note: This is using inline styles and arrow functions, which is not best, but for simplicity of the demo its enough, you could also you a className instead, its up to you ;)
You got the idea...

Categories

Resources