Dynamic loading of locally stored images with react native - reactjs

Problem with dynamic loading of image resources within a loop/list.
I have all my static local resources required as such:
assets/images.js
const images = {
appLogo: require('./app-logo.png'),
cardOne: require('./cards/card-1.png'),
cardTwo: require('./cards/card-2.png'),
...
cardForty: require(./cards/card-40.png)
}
export default images;
Then in my list screen:
...
import images from '../assets/images';
...
renderListItems(item) {
const image_name = `images.card${item.cardName}`;
console.log(image_name); // images.cardOne, images.cardTwo etc..
return (
<ListItem avatar>
<Thumbnail square size={80} source={image_name} /> // This is nativebase component which wraps the RN image component
<Body>
<Text>{item.name}</Text>
</Body>
<Right>
<NBIcon name="arrow-forward" />
</Right>
</ListItem>
);
}
...
No resources get loaded. Yet if I change the source={image_name} to source={images.cardOne} directly (where images.cardOne is the exact same as image_name variable on the first iteration) it works - except for the fact that they all have the same image.
I also tried using {{ uri: image_name }} syntax but nothing happens there too.
There doesn't seem to be any solution to this, other than creating a massive switch statement

Well that's because image_name is a string with the value of images.cardOne whereas images.cardOne is also a string but with the value of the actual path of the images in your file system (e.g ./app-logo.png). So if you want to load images object dynamically to image_name, you should use the bracket notation like so:
const image_name = images[`card${item.cardName}`];
That way image_name will now point to the path of your images (e.g ./app-logo.png).

Related

Can Dynamic and Constantly changing image URL work with Next/image

Can Next/Image use empty string variables for the src that'd get set later via an API?
I have an image url that I'd retrieve from an API. so the image src gets set after runtime. By default it's an empty string '' and then using SWR later it gets set to the full image url, eg https://i.imgur.com/Thgw1b.png
However, I get a build time error, Error: Image is missing required "src" property. Make sure you pass "src" in props to the `next/image` component. Received: {} despite having src already set. The same error occurs if src='' as well.
const myComponent = ({imageURL = ''}) => {
// imageURL starts off as '', then the parent updates that value to a proper image url when the API returns a url value.
return (
<>
// TODO: Fix build time error saying no src is set, despite being set to '' initially
<Image src={imageURL} alt='Dynamic Image' layout='responsive'/>
</>
);
}
Can Next/Image src images be set fully dynamically? Where it starts as an empty string then the src url gets populated later?
I've seen some answers suggesting useServerSide Props, but that won't work in my use case as the image url API gives a different image url every X hours (Hence using SWR). So just loading in once doesn't work.
Note that using <img> tags works perfectly. Initially there's no image, then after the image url gets set to the variable, the img tag loads the image in.
Try rendering the Image conditionally like so :
return (
<>
{imageUrl &&
<Image src={imageURL} alt='Dynamic Image' layout='responsive'/>
}
</>
)

Gatsbyjs image with Webp and fallback to jpg using picture tag not working

I'm using Gatsbyjs image in my react website I tried adding fallback to jpg using the picture tag but its not working, it's just loading the jpg file here is the code
<Box {...portfolioImage}>
<picture>
<source
srcset={
(portfolioItem.image !== null) | undefined
? portfolioItem.image.childImageSharp.fluid
: {}
}
type="image/webp"
alt={`PortfolioImage-${index + 1}`}
/>
<Image
fluid={
(portfolioItem.imageFallback !== null) |
undefined
? portfolioItem.imageFallback
.childImageSharp.fluid
: {}
}
alt={`PortfolioImage-${index + 1}`}
/>
</picture>
</Box>
The data
image {
childImageSharp {
fluid(quality: 100) {
...GatsbyImageSharpFluid_withWebp
}
}
}
imageFallback {
childImageSharp {
fluid(quality: 100) {
...GatsbyImageSharpFluid
}
}
}
The Gatsby image is a component itself, not a data to be placed inside a srcSet attribute. In your case, you should render one component or another based on the portfolioItem.image.childImageSharp.fluid data, depending on if exist or not. In addition, those ternary conditions seem odd to me.
Assuming that your GraphQL queries work as expected and are retrieving the data. I would suggest simplier like:
{portfolioItem.imageFallback.childImageSharp.fluid
? <Image fluid={portfolioItem.imageFallback.childImageSharp.fluid} alt={`PortfolioImage-${index + 1}`} />
: <picture><source srcSet={portfolioItem.imageFallback} alt={`PortfolioImage-${index + 1}`} /></picture>
}
With the snippet above you simply render the <Image> (from Gatsby image) if the data exist or the <picture> fallback image if not.
Wrapping the Gatsby Image inside a <picture> tag is not as useful as you may think since inside the image component will be a bunch of nested <div>s with the own JavaScripts fallbacks and blurs. This will change the default children of your <picture> tag causing potential issues or layout bugs.
Check for data is not the point, I set the data I need to check if the
browser supports webp image format which is what the picture tag is
supposed to do but it seems not to be working with dynamic images or
images that are loaded from JSON/grahql
Gatsby Image handles it automatically. From their documentation:
If you want to automatically use WebP images when the browser supports
the file format, use the withWebp fragments. If the browser doesn’t
support WebP, gatsby-image will fall back to the default image format.
need to test this again but pretty it did not work on safari
There's a known bug in Safari (or MacOS devices) with triggering of the intersection observer. To polyfill it:
yarn add intersection-observer
In your gatsby-browser.js:
export const onClientEntry = async () => {
if (typeof IntersectionObserver === "undefined") {
await import("intersection-observer");
console.log("IntersectionObserver polyfilled ;)");
}
};

React: Using State Variable In Image Src?

So I've exported all of the images in my image folder by using an index.js inside the same folder and writing exports such as export const Image = require("./image.png");. I then imported said images into my React app with import { Image, Image2, Image3 } from from "./imageFolder";
When I use the imported images as src values in my image tags, they work just fine so I know I've properly imported my image. The big issue that I have though is I've been trying to utilize the value of a state variable in the file to dynamically render a different image based on the state. The state variable's values are varied due to its values deriving from a database request that's stored in a state array.
{
Object.keys(this.state.videos).map((video, index) => {
return (
<div key={index}>
<p>Event: {this.state.videos[video].eventName}</p>
<p>P1 Character: {this.state.videos[video].p1Character}</p>
<p>P2 Character: {this.state.videos[video].p2Character}</p>
</div>
);
})
}
Say that in this instance, the value of {this.state.videos[video].p1Character} is equal to "Image" - which corresponds with the name of the image I imported above. So why can't I do <img src={this.state.videos[video].p1Character} />? Is it possible to do what I'm trying to do?
You cannot do it becaue the p1Character is a string and not a live variable.
You could however import the images as
import * as Images from from "./imageFolder";
and then use the p1Character to reference the image in the Images.
<img src={Images[this.state.videos[video].p1Character]} />
Unless I don't understand what you mean, I don't see how it would be possible to have this this.state.videos[video].p1Character equal to Image/Image2/Image3 if you have just save a reference to them as a string because you are literally just going to be writing src="Image/2/3".
The best thing to do would to be store a unique key string for the images on a record and then just have a simple object map in your component like
const myImageMap = {
image1: Image,
image2: Image2,
image3: Image3
}
/////
///// somewhere in your render
/////
<img src={myImageMap[this.state.videos[video].p1Character]} />
They key is that we are mapping to the strings to actual imported images

Add image to the DOM dynamically in react

I have a socket connection that updates a binary data.
By click I would like to update an image src , the images are created blank with empty src and with id , but I did not found how do I doing something like :
$('imageId').src = 'new src' like in Jquery
I have array of images so I cant define per each image this.ref or something
my socket code: // here I want to update the specific image
divSocket.on('data', (data) => {
var bytes = new Uint8Array(data);
this.setState({
imageSrc : someBufferFunction(bytes)
})
});
my render code
{ this.props.list.map((item,i) =>(
<div className="img">
<img id={`cam${i}`} src={`data:image/jpeg;base64,${this.state.imageSrc}`} />
</div>
))}
the problem is that this.state.ImageSrc will update all images and will show socket data (video) in all the images
I can create an image with specific id in loop but how do I update specific image via props/state
You're using an array to display images ... from props ... this.props.list
This list should contain data for each image ... but item argument isn't used in .map rendering.
I need to make a placeholder
Assuming that props.list doesn't contain any data ... used as loop counter ... renders placeholders only ... you need:
an array of src in local state (this.state.sources = [];)
you should render images using key prop:
{ this.props.list.map((item,i) => (
<div className="img" key={`cam${i}`} >
<img id={`cam${i}`} src={this.state.sources[i]} />
</div>
))}
you can use placeholder image for empty 'cells'
<img id={`cam${i}`} src={this.state.sources[i] ? this.state.sources[i] : "url_somePlaceholder.jpg"} />
New image from socket needs to update an array element using index - not common one for all images in this.state.sources - see React: how to update state.item[1] in state using setState? for inspirations.
If assumed earlier props.list contains image sources at start - copy values into state (in componentDidMount, componentDidUpdate or static getDerivedStateFromProps )

Can't pass relative img src route in React + Webpack

I can't dynamically pass relative img src route in React + Webpack with this.props.
This is a very simplified part of the parent component. It iterates some data list and generates ImgComponents passing props. Here is only tiny part of it:
return (
<div>
<ImgComponent srcProp={videolist.anotherImage.src} />
</div>
);
The ImgComponent has:
render() {
return (
<div>
<img src={`${this.props.srcProp}`} />
</div>
);
}
In console I get exactly the same route as i pass with this.props.srcProp, but it would not find the folder and the img there. As if webpack does not load the img.
Here is the console:
<img src="framework/assets/images/cover-bigbuckbunny.png" class="_2WcF9ZmcK-9bQX6jKk18Y_" data-reactid=".0.1.1:$comedy.0.0.$0.0.0.0">
No matter what route i indicate, the img is never found in the folder.
Here is the webpack config for png:
{ test: /\.png$/, loader: "url-loader?mimetype=image/png" }
BTW. It works fine if i require the file, like:
<img src={require ('framework/assets/images/cover-bigbuckbunny.png')} />
or indicate some remote route, like http://route.to.some.img
Seems like webpack does not load it. What should i do to dynamically load local img files by dynamically passing src with {this.props.src} ? As I can see, the loader loads img fine if i indicate the file with require. But this way i cannot do it dynamically, as require does not take variables.
What I managed to do is to require('../../assets/images/myFirst.img') in the object, containing the routs to the locally stored files:
in playlist.js
export default (
{
cartoons: [{
images: {
poster: require('../../assets/images/myFirst.png')
},
streams: [{
type: 'mp4',
url: 'http://media.w3.org/2010/05/bunny/movie.mp4'
}]
});
Then I work with this list as with any object:
import playlist from '../../playlist';
and iterate this object in a usual manner. The image will be there.
Webpack will not traverse your code to find and convert all possible references to files.
Consider following code:
<img src={'/foo/bar/baz.jpg'} />
It is your responsibility (perhaps using a build target) to ensure that baz.jpg is copied into the foo/bar directory under your web app root.

Resources