Unable to load images dynamically in react app - reactjs

I have this component :-
const CollectionItem = ({ item }) => (
<div className='collection-item'>
<div
className='image'
style={{
backgroundImage: `url(${item.imageUrl})`
}} />
</div>
</div>
)
my images urls are like ../../assets/images/imageName.jpg
i have tried loading a an image in the css file associated with this component with this exact url. It is working with css, but not in jsx. Please help.

Generally, how you load images in react is to import the image from the specified folder (webpack converts it into the correct source behind the scenes), and then to use that imported variable as the src of the image.
import imgSource from "../../assets/images/imageName.jpg";
const CollectionItem = ({ item }) => (
<div className='collection-item'>
<div
className='image'
style={{
backgroundImage: `url(${imgSource})`
}} />
</div>
</div>
)
EDIT
In the cases where the import depends upon the props, you could simple dynamically import the image within the function itself:
const CollectionItem = ({ item }) => (
import imgSource from `${item.imageUrl}`;
<div className='collection-item'>
<div
className='image'
style={{
backgroundImage: `url(${imgSource})`
}} />
</div>
</div>
)
In the case that it does not work, you can try using require instead
const imgSource = require(item.imageUrl);

Related

React is not dynamically loading images

I am trying to dynamically load images in a map function but it won't return anything.
I can get it to load a single image if I import it at the top of the page and hardcode the src but I have tried every solution I can find to do it dynamically and none of them work.
Here is what the code looks like. I am passing props with the title of the PNGs but nothing will load.
const Project = (props) => {
const proj = props.proj
return (
<div >
{proj.map(({title, id}) =>{
return(
<div>
<div className="..." key={id}>
<img
src={require(`../Assets/${title}.png`).default}
alt={`Image of ${title} hompage`}
className='object-cover'
/>
</div>
</div>
)
})}
</div>
)
}
export default Project;
The app was set up with create react app. I tried setting up a library but it didn't load the images either.

Image not getting rendered in react application

Unable to render images in react, In browser console, image names are displayed correctly but on UI it is not displayed. Also, src attribute is missing from img tag after inspecting element. Please assist. Here is Sample Script
function importAll(r) {
let images = {};
r.keys().map((item, index) => { images[item.replace('./', '')] = r(item); });
return images;
}
const get_images = importAll(require.context('../../images', true, /\.(png|jpe?g|svg)$/));
const images = Object.entries(get_images).map(module => module[1].default);
return (
<div className="product">
<div>
<Row>
{products.map(product =>
<Col span={6} key={product.productId}>
<div >
<div>{console.log(product.productImageName)}
{<Image src={images[product.productImageName]} width={200}
height={200} />}
</div>
</div>
</Col>
)
}
</Row>
</div>
</div>
)
You don't need to import images. if images are part of your repository then you can use the relative path from the src directory. e.g assuming the images in under src
const path = `images/${[product.productImageName]}`;
<Image src={path} />
You should try and check if profile exist. Like this:
{profile && profile.map((...
//Or
{profile?.map((...

React accordion with correlating image outside accordion section

I can't find any examples of accordions where the active class is related to an element outside of the accordion. I'm trying to get an image to change on the side of the accordion, where each image is related to a specific object. I managed to get something working using absolute positioning, but I'm looking for a more elegant solution so I can manipulate styling better.
I can get it to work while the image is inside the accordion under the info text, but can't figure out the styling issue. I think I need to do some refactoring or do away with the array mapping to get it to work but I'm not sure.
Here is a codesandbox of more or less what I want to achieve but without the restriction of absolute positioning - https://codesandbox.io/s/ecstatic-taussig-f084t?file=/src/App.js
You can remove your img tag from your renderedItems and do something like this:
import React, { useState } from "react";
const Accordion = ({ items }) => {
const [activeIndex, setActiveIndex] = useState(0);
const onTitleClick = (index) => {
setActiveIndex(index);
};
const renderedItems = items.map((item, index) => {
const active = index === activeIndex ? "active" : "";
return (
<div key={item.title}>
<div className={`title ${active}`} onClick={() => onTitleClick(index)}>
<i className="dropdown icon"></i>
{item.title}
</div>
<div className={`content ${active}`}>
<p>{item.content}</p>
</div>
</div>
);
});
return (
<div className="container-gallery">
<div className="ui styled accordion">{renderedItems}</div>
<img
className={`content `}
src={`${items[activeIndex].image}`}
style={{
height: "200px",
width: "200px"
}}
alt="img"
/>
</div>
);
};
export default Accordion;
And for the style I don't know what you are using so I made css for the example:
.container-gallery{
display:flex;
flex-wrap:no-wrap;
justify-content: space-between;
}
here a sandBox link

How can I insert a React component inside an HTML string and then render it with dangerouslySetInnerHTML?

I'm using NextJs. I have an html string that is fetched from the server. It represents a blog post and contains several <img> tags. I'm currently rendering the post like this:
const blogpostHtml = "..." // an html string that comes from the server
return (
...
<div
dangerouslySetInnerHTML={{__html: blogpostHtml}}
/>
...
)
And it works fine. However, I'd like to add functionality to the images. I found this library that accomplishes what I want with an uncontrolled component:
...
<Zoom>
<img
alt="some alt"
width="500"
src="the image url"
/>
</Zoom>
...
However, I noticed that I can't simply insert the Zoom tags because it's interpreted as a raw html tag instead of a component. And if I try to render it to a string it loses functionality.
let html = ReactDOMServer.renderToString(
<Zoom>
<img
alt="some alt"
width="500"
src="the image url"
/>
</Zoom>
)
return (
...
<div
dangerouslySetInnerHTML={{__html: html}}
/>
...
)
As you can see in the image, the resulting html is the same as using the Zoom component as intended, but the button loses its event
So how can I combine the html string from the server and the uncontrolled Zoom component to achieve what I want?
Thanks to William's answer in the comments I got this solution
import Zoom from 'react-medium-image-zoom'
import ReactDOM from 'react-dom'
import { useEffect } from 'react'
const Index = () => {
const html = `
<p>This is some text</p>
<img src="some-img-src.jpg"/>
<p>More text here</p>
`
useEffect(() => {
// 1. extract imgs and src
const imgs = document.getElementsByTagName('img')
const srcArray = Array.from(imgs).map(img => img.src)
// 2. wrap images with div then replace each div using ReactDOM.render
for (let i = 0; i < imgs.length; i++) {
const wrapper = document.createElement('div')
wrapper.setAttribute('id', `img-${i}`)
imgs[i].parentNode.insertBefore(wrapper, imgs[i])
wrapper.appendChild(imgs[i])
ReactDOM.render(
<Zoom>
<img src={srcArray[i]} />
</Zoom>,
document.querySelector(`#img-${i}`)
)
}
}, [])
return (
<>
<div
dangerouslySetInnerHTML={{
__html: html
}}
/>
</>
)
}
export default Index

Access Gatsby Component from a function

I am trying to access a Gatsby component (Anime) from outside of it.
Can not figure out what instance name this would have or how to name it.
Here is my code:
import React from 'react'
import PropTypes from 'prop-types'
import PreviewCompatibleImage from '../components/PreviewCompatibleImage'
import Anime from 'react-anime';
import VisibilitySensor from 'react-visibility-sensor';
function onChange (isVisible) {
console.log('Element is now %s', isVisible ? 'visible' : 'hidden')
}
const FeatureGrid = ({ gridItems }) => (
<div className="columns is-multiline">
<VisibilitySensor onChange={onChange}>
<Anime delay={(e, i) => i * 100}
scale={[.1, .9]}
autoplay={false}>
{gridItems.map(item => (
<div key={item.text} className="column is-3">
<section className="section">
<div className="has-text-centered">
<div
style={{
width: '160px',
display: 'inline-block',
}}
>
<PreviewCompatibleImage imageInfo={item} />
</div>
</div>
<p>{item.text}</p>
</section>
</div>
))}
</Anime>
</VisibilitySensor>
</div>
)
FeatureGrid.propTypes = {
gridItems: PropTypes.arrayOf(
PropTypes.shape({
image: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
text: PropTypes.string,
})
),
}
export default FeatureGrid
I want to get the animation to trigger from the onChange function.
How do I get the name or set the name of the Anime component so I can access it from the function?
Or is there another way I should address this?
Using a Gatsby starter netlify CMS as the base, so extending on their code, but seems that const is not the route I should take.
I want the animation to trigger when it becomes visible.
Any suggestions?
According to the docs react-visibility-sensor :
You can pass a child function, which can be convenient if you don't need to store the visibility anywhere
so maybe instead of using the onchange function you can just pass the isVisible parameter, something like:
<VisibilitySensor>
{({isVisible}) =>
<Anime delay={(e, i) => i * 100}
// the rest of your codes here ...
</Anime>
}
</VisibilitySensor>
Otherwise you can convert this function to a react component and set states, etc..

Resources