How to handle missing image in react 17? - reactjs

I'm getting users data from an api which the profile pictures path could be invalid, so i was able to cover the part of using a default image, but the 404 error of the missing picture is still exists ... i wonder how can i prevent it. I went over ALL the solutions and still couldn't find a good one.
Here is my component that renders the image
import React, { useState } from 'react';
const Image = props => {
const { image } = props;
const [imageLoading, setImageLoading] = useState(true);
const imageLoading_Error = () => {
setImageLoading(false)
}
return (
<div item>
<img src={imageLoading
?
`https://myusers.com/user/${image}` // don't mind the address
:
`${window.location.origin}/assets/default.png`}
onError={() => imageLoading_Error()}
/>
</div>
)
}
export default Image;

Related

Trying to show a random picture from Unsplash

Hi this is my first React app im trying to build.
I'm trying to show a random image in React but i can't get
the image to show.
import React from 'react';
function ImageList(props) {
console.log(props);
return (
<div><img src={props} alt="cat"/></div>
);
}
export default ImageList;
the props looks like this:
props: "https://images.unsplash.com/photo-1568152950566-c1bf43f4ab28?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzNTkxNzd8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NjE3NTY3NTc&ixlib=rb-1.2.1&q=80&w=400"
When i inspect the img it says object Object.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import './App.css'
import ImageList from './ImageList';
const App = () => {
const [cats, setCats] = useState("");
async function onSearchSubmit(term) {
const response = await axios.get('https://api.unsplash.com/photos/random/',{
params: { query: term},
headers:{
Authorization: 'Client-ID //here i just where i put my key in '
}
});
setCats(response.data.urls.small);
}
return(
<div className='App'>
<button onClick={() => {onSearchSubmit("cat")} }>
Show a cat picture
</button>
<ImageList props = {cats}/>
</div>
);}
export default App;
This is the rest of the code.
I am thankful for your help. Cheers!
props it's just the name of your prop.
Look at this row:
<ImageList props = {cats}/>
You shouldn't use the props name for your props. Use some meaningful name instead, like cats
<ImageList cats = {cats}/>
// And in ImageList
const ImageList = ({cats}) => {
// do something with cats. Now it must be a string
}
OR
// props is an object
const ImageList = (props) => {
const cats = props.cats
// do something with cats. Now it must be a string
}

Unable to seekTo or skip to time using <video> for MP4 files

I can't seem to be able to skip to a particular time using ReactPlayer.
Here's my code.
import React, { useRef } from "react";
import ReactPlayer from "react-player";
function VideoPlayer(props) {
const { video, setCurrTime, setAddComment } = props;
const playerRef = useRef();
const writeComments = () => {
if (playerRef.current) {
setCurrTime(playerRef.current.getCurrentTime());
setAddComment(true);
}
};
return (
<div className="player-wrapper">
<ReactPlayer
ref={playerRef}
className="react-player"
width="100%"
height="100%"
url={`http://127.0.0.1:8000${video.video}`}
controls
onPause={writeComments}
/>
</div>
);
}
export default VideoPlayer;
I suspect it might be the file format, MP4.
Unfortunately playerRef doesn't get set to a value you can use.
First caveat: https://github.com/cookpete/react-player/issues/1508
This is an open issue about React's StrictMode often enabled on new projects for React 18. It breaks setting src on the player so it doesn't work. If you upgrade to React 18, the simplest but not ideal solution is to disable React.StrictMode.
If your player is loading, you're on React 17 or you are not using StrictMode.
So if your video is loading, use ReactPlayer's onReady to set your playerRef. player passed into your onReady handler is the actual instance of ReactPlayer which has the methods you are looking for.
import React, { useRef } from "react";
import ReactPlayer from "react-player";
function VideoPlayer(props) {
const { video, setCurrTime, setAddComment } = props;
const playerRef = useRef();
const writeComments = () => {
if (playerRef.current) {
setCurrTime(playerRef.current.getCurrentTime());
setAddComment(true);
}
};
return (
<div className="player-wrapper">
<ReactPlayer
className="react-player"
width="100%"
height="100%"
url={`http://127.0.0.1:8000${video.video}`}
controls
onPause={writeComments}
onReady={(player) => playerRef.current = player}
/>
</div>
);
}
export default VideoPlayer;

Constant Rerender when downloading an image (React)

I am trying to download an image from AWS, display it in my React component, and then on a button click, load a new image. The problem I am facing is that every time I go to load a new image, the page loads image after image, and won't stop rerendering with new images.
Here is my code for the landing page:
import React from 'react';
import Background from './Media/marmaduke2.jpg';
import Comic from'./Comic.js';
import { useState, useEffect } from 'react';
export default function RandomarmLanding() {
const [score, setScore] = useState(0)
const [isReal, setIsReal] = useState(false)
const [caption, setCaption] = useState('')
async function getComics() {
const response = await fetch('http://127.0.0.1:5000/comics')
const data = await response.json()
setCaption(data['caption'])
setIsReal(data['is_real'])
}
function GuessYes() {
if (isReal == true) {
setScore(score + 1)
}
}
function GuessNo() {
if (isReal == false) {
setScore(score + 1)
}
}
useEffect(() => {
getComics()
},[])
return(
<div style={{backgroundImage: `url(${Background})`}}>
<Comic caption={caption}/>
<button onClick={GuessYes}>Yes</button>
<button onClick={GuessNo}>No</button>
<button onClick={getComics}>get comics</button>
<h2>{score}</h2>
</div>
)
}
Here is my code for the Comic component:
import React from 'react';
import comic from './Media/comic.png';
export default function Comic (props) {
return(
<div>
<img src={comic}/>
<h1>{props.caption}</h1>
</div>
)
}
Here is the code that is actually downloading the image:
import boto3
def download_comic(num):
s3 = boto3.resource('s3')
s3_client = boto3.client('s3')
bucket = s3.Bucket('bucket_name')
s3_client.download_file('bucket_name',f'{num}.png', '/path/my-app/src/components/Randomarm/Media/comic.png')
Any thoughts on what might remedy this?
Thanks for the help!
EDIT
Instead of downloading the image to display it, I am just showing the image from my s3 bucket, using <img src=bucketimage.gif'/>. This way I avoid the constant rerendering all together.
I believe it's because of the state being changed in useEffect inside the method getComics where you are setting the caption.
I solved it. Instead of downloading the image, I am just displaying the image from my s3 bucket. That way I avoid downloading the image all together.

I am getting this error while making a small app using react can someone help me this

I am new to react I am making a small app using reactjs when I added this file and run the code it is giving this error no syntactical error are shown.
this is the code which I have written.
import React from { react }
import Card from "./Card"
const CardList = ({ robots }) => {
//const cardComponent=robots.map((user,i)=>{
return (
// key prop should have something that should not be changed
<div>
{
robots.map((user, i) => {
<Card
key={i}
id={robots[i].id}
name={robots[i].name}
email={robots[i].email} />
})
}
</div>
)
}
export default CardList
the app should run smooth.thsi is the error I am getting
What I understand is. Your import is not right. If there is another please add code for more info
import React from 'react';//not what you import
import Card from "./Card";
const CardList = ({ robots }) => { //const cardComponent=robots.map((user,i)=>{ return ( // key prop should have something that should not be changed { robots.map((user, i) => { }) } ) }

Import image dynamically in React component

I have an Articles component that shows a blog page with listed articles.
render() {
const articles = {
...this.state.articles
}
const article = Object.keys(articles).map(cur => {
return <Article
key={this.state.articles[cur].id}
imgName={this.state.articles[cur].thumb}
title={this.state.articles[cur].title}
meta={this.state.articles[cur].meta}
clicked={() => this.detailedHandler(this.state.articles[cur].id)}
detailed={this.state.articles[cur].detailed} />
});
As you can see I pass image name with props to Article component.
I want then to display the appropriate image for each article.
How do I import an image in Article component based on the props I receive (props.imgName) from Articles component?
I used context.
const images = require.context('../../../assets/img', true);
loadImage = imageName => (assets(`./${imageName}`).default);
<img src={loadImage("someimage.png")} alt="" />
I don't know if this is an optimal solution, but it works.
You can load images dynamically from the API response with dynamic imports that is Stage 3 proposal as of now.
The resulting code should look something like:
loadImage = imageName => {
import(`./assets/${imageName}.jpg`).then(image => {
this.setState({
image
});
});
};
render() {
const { image } = this.state;
return (
<Fragment>
{image && <img src={image} alt="" />}
</Fragment>
);
}
View Codesandbox Demo
This feature is supported out of the box in create-react-app, If using other systems, you can use the Babel plugin
For anyone looking for a modern approach using async-await and custom react hooks, I found a pretty slick solution. Create a file called useImage.js and paste the following code:
import { useEffect, useState } from 'react'
const useImage = (fileName) => {
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
const [image, setImage] = useState(null)
useEffect(() => {
const fetchImage = async () => {
try {
const response = await import(`../assets/img/${fileName}`) // change relative path to suit your needs
setImage(response.default)
} catch (err) {
setError(err)
} finally {
setLoading(false)
}
}
fetchImage()
}, [fileName])
return {
loading,
error,
image,
}
}
export default useImage
Then just import the custom hook into your image component, mine looks something like this:
import useImage from '../../hooks/useImage'
import Typography from './Typography' // simple plain-text react component
const Image = ({ fileName, alt, className, ...rest }) => {
const { loading, error, image } = useImage(fileName)
if (error) return <Typography>{alt}</Typography>
return (
<>
{loading ? (
<Typography>loading</Typography>
) : (
<img
className={`Image${
className
? className.padStart(className.length + 1)
: ''
}`}
src={image}
alt={alt}
{...rest}
/>
)}
</>
)
}
export default Image
The nice thing about this solution is that no matter where your component is in relation to your assets folder, the react hook is always in the same place, so the relative path stays the same.
there are my way, works nicely:)
import React, {useState} from "react"
const getFavorites = (props) => {
const {item, favouritesNote} = props;
const [image, setImage] = useState("");
(function (imageName) {
import(
`../../../../assets/images/chart/favorite${imageName ? "_active" : ""}.png`
).then((image) => setImage(image.default));
})(favouritesNote[item.id]);
return (
<div>{image && <img alt="" className="img-responsive" src={image} />}</div
)
}
Note: All these comments work complementary with the #jadenRose hook solution which is a great abstraction.
You can import the images dynamically with the native js dynamic import('') , there's no need for React Lazy.
However, you have to be aware of the path/content you pass to the import(path) because depending on how you are planning to include the images to import in the final bundle there could be restrictions. There are two main ways:
Note: This is for Rollup, in Webpack i didn't try it but should be similar
a)- Making rollup automatically include the possibles files to import while creating the bundle using the official plugin https://www.npmjs.com/package/#rollup/plugin-dynamic-import-vars please read the doc and notice how there are important restrictions in the 'path' string, essentially you should just set the file name in the variable, the rest of the path have to be fixed in the import('') in order to provide rollup a restricted scope to import. eg:
OK
import(../assets/img/${fileName}.svg)
Wrong
import(filePath)
b)- Include in the bundle programmatically the files you can dynamically import example
//rollup.config.js
import copy from 'rollup-plugin-copy';
plugins: [
copy({
targets: [ { src: 'src/assets/icons/*', dest: 'lib/assets/icons' },],
}),
…
],
With this option b) you have no restrictions on the variable content but have to be careful with what you included in the bundle.
Conclusion: You can use dynamic import(...) but if you not properly handle the files inclusion on the bundle, it can be possible they are excluded and then the dynamic import will fail in the consumer.
I found this worked best for me:
I created an index file inside the images folder. there I imported all the images I have and created a class component with the variables assigned to each image import. this is because when we import an image in react using the import statement, that is, import someImage from './somewhere' react assigns the 'someImage' variable to a module with a 'static media' address, my terminology there might be wrong. Here is the example:
import image13_1 from './image13_1.png';
import image13_2 from './image13_2.png';
import image13_3 from './image13_3.png';
import image13_4 from './image13_4.png';
import image13_5 from './image13_5.png';
import image13_6 from './image13_6.png';
import image13_7 from './image13_7.png';
export class IMG{
1= image13_1
2 = image13_2
3 = image13_3
4 = image13_4
5 = image13_5
6 = image13_6
7 = image13_7
}
export default IMG;
from here I just import the IMG class and create an instance of it and call the image number a property:
var img = new IMG()
console.log('img',img[1]

Resources