Im working on a project and only started recently with React.So far i made card component that is dynamically rendering data from js-file with a mapped function.One of the data being rendered are (stored in array) images where im displaying the first img and setting up a onClick function that opens the modal.
And this is where i'm stuck.Modal opens with non targeted img, where i would like to display the clicked image in modal first and pass the rest of the images of that array that can be clicked through.Like a image slider.When i console.log the images i can see im getting all the arrays in modal but i don't know how to set them accordingly.
I would appreciate some input how to go about the problem and what i am doing wrong.
I have a parent component which is receiving the data from js-file.
class Room extends Component{
constructor(){
super();
this.state = {
data: roomData,
}
}
render(){
return (
<>
<div>helo from room page</div>
<RoomCards data={this.state.data} />
</>
);
}
}
this is the card Component
import Modal from "../components/modal";
class RoomCards extends Component{
constructor(){
super();
this.state = {
showModal: false,
};
}
getModal = ()=> {
this.setState({ showModal: true })
}
hideModal = () => {
this.setState({ showModal: false });
}
render(){
return (
<>
{
this.props.data.map((data) => {
return <div className="card__container" key={data.id} >
<div className="card">
<h2 className="card__title">{data.name}</h2>
<p className="card__description">{data.paragraph}</p>
<ul><li>{data.list[0]}</li></ul>
<ul><li>{data.list[1]}</li></ul>
<ul><li>{data.list[2]}</li></ul>
<ul><li>{data.list[2]}</li></ul>
<div className="card__img">
<img src={data.image}
onClick={() => this.getModal(data)}
alt="" />
<Modal
show={this.state.showModal}
onHide={() => this.hideModal()}
image={data.image} />
</div>
</div>
<button className="card__btn">Bestill overnatting</button>
</div>
})
}
</>
)
}
}
export default RoomCards
the modal component
import React, { Component } from "react";
import "../styles/Room.scss";
class Modal extends Component {
constructor(){
super();
this.state = {
index:0
};
}
next =() => {
if({index : this.state.index}){
this.setState({index: this.state.index + 1});
}else {
this.setState({index: this.state.index})
console.log("heloo i am at index");
}
}
prev=()=>{
if(this.state.index === 0 || this.state.index === -1) {
console.log("hi")
}else {
this.setState({index :this.state.index - 1});
}
}
render() {
console.log(this.props.image)
return (
<React.Fragment>
{this.props.show && (
<div className="modal">
<img alt="" src={this.props.image[this.state.index]} key={this.state.index} />
{/* <img alt="" src={this.props.image[1]}/> */}
<button onClick={this.props.onHide}>Close Modal</button>
<button onClick={this.prev}>👈</button>
<button onClick={this.next}>👉</button>
</div>
)}
</React.Fragment>
);
}
}
export default Modal;
and the data from js-file
const roomData = [
{
id:1,
name: "standard room something new",
paragraph:"Hotellets standard enkeltrom passer perfekt til deg som reiser alene. Rommene er møblert med enten en 90 cm seng eller en 160 cm bred seng, skrivebord, lenestol, og baderom med dusj ",
list: ["wifi", "tv", "ikke royken"],
image: ['https://images.unsplash.com/photo-1585255318859-f5c15f4cffe9?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=500&ixlib=rb-1.2.1&q=80&w=500',
'https://images.unsplash.com/photo-1584226761916-3fd67ab5ac3a?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=500&ixlib=rb-1.2.1&q=80&w=500',
'https://images.unsplash.com/photo-1585084335487-f653d0859c14?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=500&ixlib=rb-1.2.1&q=80&w=500',
'https://images.unsplash.com/photo-1583217874534-581393fd5325?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=500&ixlib=rb-1.2.1&q=80&w=500',
]
},
{
id:2,
name: "standard room something new",
paragraph:"Hotellets standard enkeltrom passer perfekt til deg som reiser alene. Rommene er møblert med enten en 90 cm seng eller en 160 cm bred seng, skrivebord, lenestol, og baderom med dusj ",
list: ["wifi","tv", "ikke royken"],
image: ['https://images.unsplash.com/photo-1585179292338-45ba1f62f082?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=500&ixlib=rb-1.2.1&q=80&w=500',
'https://images.unsplash.com/photo-1584753987666-ead137ec0614?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=500&ixlib=rb-1.2.1&q=80&w=500',
'https://images.unsplash.com/photo-1583217874534-581393fd5325?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=500&ixlib=rb-1.2.1&q=80&w=500',]
},
{
id:3,
name: "standard room something new",
paragraph:"Hotellets standard enkeltrom passer perfekt til deg som reiser alene. Rommene er møblert med enten en 90 cm seng eller en 160 cm bred seng, skrivebord, lenestol, og baderom med dusj ",
list: ["wifi", "tv", "ikke..."],
image:['https://images.unsplash.com/photo-1584691267914-91c0bee55964?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=500&ixlib=rb-1.2.1&q=80&w=500',
'https://images.unsplash.com/photo-1585084335487-f653d0859c14?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=500&ixlib=rb-1.2.1&q=80&w=500']
},
{
id:4,
name: "standard room something new",
paragraph:"Hotellets standard enkeltrom passer perfekt til deg som reiser alene. Rommene er møblert med enten en 90 cm seng eller en 160 cm bred seng, skrivebord, lenestol, og baderom med dusj ",
list: ["wifi", "tv,"],
image: ['https://images.unsplash.com/photo-1583217874534-581393fd5325?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=500&ixlib=rb-1.2.1&q=80&w=500']
}
]
export default roomData;
The main issue here is that you are rendering a modal for each data
element mapped but using a single showModal
state that ends up toggling all of them open/close together.
I suggest storing the the specific data you want to display in the modal into the state.showModal
state, with an initial value null
. Conditionally render a single Modal
component.
class RoomCards extends Component {
state = {
showModal: null
};
getModal = (data) => {
this.setState({ showModal: data });
};
hideModal = () => {
this.setState({ showModal: null });
};
render() {
return (
<>
{this.props.data.map((data) => {
return (
<div className="card__container" key={data.id}>
<div className="card">
<h2 className="card__title">{data.name}</h2>
<p className="card__description">{data.paragraph}</p>
<ul>
{data.list.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
<div className="card__img">
<img
src={data.image}
onClick={() => this.getModal(data)}
alt=""
/>
</div>
</div>
<button className="card__btn">Bestill overnatting</button>
</div>
);
})}
{this.state.showModal && (
<Modal
onHide={this.hideModal}
images={this.state.showModal?.image}
/>
)}
</>
);
}
}
Fix up the modal to maintain valid current index value.
class Modal extends Component {
state = {
index: 0
};
next = () => {
const { images } = this.props;
this.setState(({ index }) => ({
index: Math.min(images.length - 1, index + 1)
}));
};
prev = () => {
this.setState(({ index }) => ({
index: Math.max(0, index - 1)
}));
};
render() {
const { index } = this.state;
const { images, onHide } = this.props;
return (
<div className="modal">
<img alt="" src={images[index]} />
<button onClick={this.props.onHide}>Close Modal</button>
<button onClick={this.prev}>👈</button>
<button onClick={this.next}>👉</button>
</div>
);
}
}