I'm new to React and I'm trying to create a game involving cards where a websocket returns an array of card names, and on the front end I generate the correct card images from a local directory of images. The card names returned from the websocket match the file name of the image, e.g. "map" corresponds to the image "map.jpg". I'm attempting to map over the array & create an image tag for each card name in the array. I read that the best way is to use require() and so I attempted to do something like
//inside component
let cardImgs;
...
socket.on(RECEIVED_STARTING_HAND, (hand) => {
cardImgs = hand.map(cardName => <img src= {require(`../../card_images/${cardName}.jpg`)}/>
})
...So that later on in my component I could do something like this:
return (
<div>
<h1>My hand</h1>
{cardImgs}
</div>
...
)
However, cardImgs does not render. In my return statement of my component I tested out rendering an image directly and it worked, e.g.
const map = "map"
return (
<div>
<h1>My hand</h1>
{cardImgs}
</div>
...
//this one renders!!!
<img src={require(`../../card_images/${map}.jpg`)} />
)
I created my react app with Create-React-App and I read some things that said I should reconfigure my webpack.config.js file but then I also read some things that said I should not touch it unless I needed to. I am not sure why require() works when I do it in my return statement of my component yet it's not working when given the array of image tags. Am I missing something or do you have any suggestions on better ways to dynamically load images in React? Thank you!
I recommend simply processing the state item hand in your render. When you update the value, a render will be triggered and create your images.
{hand.map((cardName, index) => (
<img key={cardName} src={`pathtoserver/card_images/${cardName}.jpg`}/>
))}
Demo
if you want render a image from a local folder you can import images that you need with import syntax and after that use it in your img tag
import card1 from '../you/path/to/image.png';
import card2 from '../you/path/to/image.png';
import card3 from '../you/path/to/image.png';
const cards = {
nameToCard1: card1,
nameToCard2: card2,
nameToCard3: card3,
}
in your socket method:
socket.on(RECEIVED_STARTING_HAND, (hand) => {
cardImgs = hand.map(cardName => cards[cardName] />
})
and in your render method:
return (
<div>
<h1>My hand</h1>
<ul>
{cardImgs.map((img) => <li><img key={img} src={img} /></li>)}
</ul>
</div>
)
i hope this help you, have a nice day.
Related
I'm facing an issue when I try to display images inside my React App component
I have all the images I need, divided by set, in this path src/cards_images/ inside root folder.
In this way I can reach for cards in different sets like:
src/cards_images/set1_MyFirstSetName_MyCard1.jpg
src/cards_images/set2_MySecondSetName_MyCard1234.jpg
I need to create images dynamically, because on this component I pass an array of objects, with the right source path. If I hard-code the same source path, it works, but if I dynamically try to create the path, React says it can't find the module.
I can't put every image inside Public folder because we are talking about several thousands of 200kb images and it won't load. Neither I can import/require every image in bulk, because it will not work aswell (still, how to filter/show them?). It has to be dynamically required and showed. How can I do it? Am I doing anything wrong on this?
import React , {Component}from 'react';
function CardDisplay({ sets }) {
return (
<div id="myDeckCardPickerContainer">
{sets?.map(settino => {
// Gives error "Module not found"
var temp = require(settino.url)
return <div key={settino.key} className='cardImageContainer'><img className='cardImagePreview' src={temp} alt={settino.Name}></img><div><span className='addCardToDeck'>➕</span>{settino.name}<span className='removeCardFromDeck'>➖</span></div></div>
// Gives error "Module not found"
return <div key={settino.key} className='cardImageContainer'><img className='cardImagePreview' src={require(settino.url)} alt={settino.Name}></img><div><span className='addCardToDeck'>➕</span>{settino.name}<span className='removeCardFromDeck'>➖</span></div></div>
// Works fine
return <div key={settino.key} className='cardImageContainer'><img className='cardImagePreview' src={require('../cards_images/set1_MyFirstSetName_MyCard1.jpg')} alt={settino.Name}></img><div><span className='addCardToDeck'>➕</span>{settino.name}<span className='removeCardFromDeck'>➖</span></div></div>
})}
</div>
)}
export default CardDisplay;
I am calling the OpenWeatherMap API and getting in the response the iconID like 01d or 04n. I've set up all the images under a local directory in /src and named them 01d.png, 04n.png etc.
I've passed this iconID via props to my Current.js component and I don't know how can I display the image with the specific id name.
E.G:
I would like to display image 01d.png if the response from the server is equal to 01d
P.S:
props.icon stores the data from the server and it is indeed good data.
import React from 'react';
import classes from './Current.module.css';
const current = (props) => {
return (
<div className={classes.Current}>
<p>Temperature: {props.temperature}</p>
<p>Minimum Temperature: {props.minimumTemperature}</p>
<p>Maximum Temperature: {props.maximumTemperature}</p>
<p>Humidity: {props.humidity}</p>
<img src={'../../icons/' + props.icon + '.png'}[enter image description here][1] alt={props.icon}/>
</div>
)
}
export default current;
Here is a screenshot of my folder structure
First of all make sure that the images folder is not out of src, then load image like
<img src={require(`../../icons/${props.icon}.png`)} />
Or if it is only one image id passed to component and no need for maping you can lazy load it when component renders.
const current = (props) => {
const pic = React.lazy(()=>import(`../../icons/${props.icon}.png`))
......
Then wrap the img tag with Suspense and <img src={pic} />
This question already has answers here:
Load images based on dynamic path in ReactJs
(4 answers)
Closed 5 years ago.
i'm passing the following as props.
const people=['Eliana','Stefania','Ahmed']
{
people.map(function(name, index){
return <Person item={index} name={name}/>;
})
}
import Eliana from '../assets/imgs/people/eliana.png'
import Stefania from '../assets/imgs/people/stefania.png'
import Ahmed from '../assets/imgs/people/ahmed.png'
export default class Person extends React.Component {
render() {
return (
<div>
<img src={this.props.name} alt=''/>
<li key={this.props.item}>{this.props.name}</li>
</div>
);
}
}
what i'm doing here is using the above strings in the array to pass to a component and then generate images from that component by using the corresponding path, however when i pass the props, they display as strings, like Eliana would display as is in the img src?
how do i get corresponding paths? some kind of string conversion probably?
i bet this is an easy one!
An easy fix for what you're asking about
<img src={require(this.props.name)} alt=''/>
But this is implying that you have the full path. What you currently have doesn't look like will work. In one way or another, each one has to end up with a path name, like this, when React interprets your code:
<img src={require('../assets/imgs/people/ahmed.png')} alt=''/>
A simple fix is to add the path as a string before your this.props.name. It's standardized so all you have to do is add the name in, like so:
<img src={require(`../assets/imgs/people/${this.props.name.toLowerCase()}.png`)}/>
Be sure to document this though. You definitely want to document this.
You could just use concatenate the entire URL besides the name, then concatenate the name prop in it's place.
<img src={require('../assets/imgs/people/' + this.props.name + '.png')}
I am using an Image component as a background in React Native and am currently providing the source prop with an image as follows, which works.
const ImageWrapper = (props) => {
return (
<Image source={require('../../../images/testingImages/cells.png')} style={styles.imageView}>
{props.children}
</Image>
);
};
However, I would like to provide the require with an interpolated string with the name of an image provided by a prop as so:
require(`../../../images/testingImages/${props.imgURL}`)
But whenever I do so (even when I create the string as a seperate variable without using ES6 and pass it into require). I get the error -
"unknown named module '../../../images/testingImages/cells.png'".
Is there away to get the image without using require? As I would love to be able to pass the image url as a prop so that I can reuse the component when I want to change the background.
Any help is much appreciated!
Hopefully somebody else can provide a solution to your exact problem because I was having the same issue, but my workaround was to pass the entire value for source as a prop. I had that as a value to a certain key for each map within a list in my scenario, so that was clean enough for me. But that may be just moving the problem up a level in your case.
First create a file with image required - React native images must be loaded this way.
assets/index.js
export const leftChevron = require('./left-chevron.png');
export const rightChevron = require('./right-chevron.png');
export const circle = require('./oval-bottom-right.png');
export const homeandgarden = require('./homeAndGarden.png');
Now import all your assets
App.js
import * as All from '../../assets';
You can now use your image as an interpolated value where imageValue is the same as named local file:
<Image style={styles.image} source={All[`${imageValue}`]}></Image>
I am not sure if it solves your issue but if your image is available over network you can use your base URL to create a URL to the image and use that URL directly inside as a source.
var fileName = "trolltunga.jpg";
var imagesBaseUrl = "https://www.w3schools.com/css/";
var image = imagesBaseUrl+fileName;
const imageURL = {url:image}
class App extends React.Component {
render() {
return (
<Image source={imageURL} style={styles.imageView}>
</Image>
);
}
}
For demo check here https://rnplay.org/apps/hEYzcA
Here is how I got round it specifically, not really a perfect answer but works fro my purpose. I think the require is called when the component loads and hence the string doesn't get a chance to interpolate to be passed. So instead I import the relevant image in the parent component of image wrapper:
import jungle from '../../images/jungle.jpg';
Then pass as a prop to Image Wrapper
<ImageWrapper image={jungle} />
Then pass this prop to the image source component:
<Image source={this.props.image} style={styles.imageView}>
{ this.props.children }
</Image>
I'm looking to render multiple modals into a single ReactDOM element. Here's the HTML structure that React renders to.
<body>
<div id="modal-socket"></div> // Insert multiple here
<div id="wrapper">
// Other content goes here
</div>
</body>
There's a long story behind why I need to render multiple components into #modal-socket but I want to do something akin to this:
ReactDOM.render(<AddMeasurableModal />, document.getElementById("modal-socket"));
ReactDOM.render(<AddMeasurableModal />, document.getElementById("modal-socket"));
ReactDOM.render(<AddMeasurableModal />, document.getElementById("modal-socket"));
Obviously this replaces the current content of #modal-socket on each render call.. So I don't get my end result. Boo.
Did a search and found a few answers on it but none meet my needs.
Cheers.
As you told in a comment, the dynamic way would be something like this
Inside of a main component you could do:
Imagine having an array like:
let myArray = [
{
prop1: 'hello world'
},
{
prop1: 'Hey there!'
}
]
//Then in the render function (you can put that array into the state or something)
render(){
return (
<div>
{myArray.map((entry,index) => {
return <AddMeasurableModal key={index} {...entry} />
})}
</div>
)
}
this will create as many AddMeasurableModal components as there are entrys in the myArray variable and add every property stored as props onto the component (In this case, every AddMeasurableModal component has access to the this.props.prop1 value, because of the {...entry} spread syntax)
Notice how I only put myArray.map() into the render function inside of {}?
React renders every array of components without further configuration inside of the render function. And Array.map() returns an array. Just make sure to return only valid react elements! When doing this, don't forget to add a uniqe key prop to each element to avoid warnings.
EDIT: in this case, the key prop is the current index in the array, but when fetching data from a server I would recommend to use a uniqe id from the database or something to avoid rendering bugs.
If you don't want to map over an array, you can just set a number of components and then loop over them, creating an array of components and put them into the render function.
Wrap your multiple modals into 1 container and render that, eg:
let modals = (
<div>
<AddMeasurableModal />
<AddMeasurableModal />
<AddMeasurableModal />
</div>
);
ReactDOM.render(modals, document.getElementById("modal-socket"));