Reputation: 35
I have problem with my react app. I have generated list of 100 items. I display every element from list using map function
<ul className="list">
{this.props.items.map((item) => {
return (
<ItemView
key={item.id}
id={item.id}
name={item.name}
strenght={item.strenght}
age={item.age}
/>
);
})}
</ul>
My item view display name, age and strenght. On mouseEnter display button which after click display modal under clicked element.
class ItemView extends React.Component {
constructor(props) {
super(props);
this.state = {
isMouseInside: false,
isModalOpen: false,
};
}
mouseEnter = () => {
this.setState({ isMouseInside: true });
};
mouseExit = () => {
this.setState({ isMouseInside: false });
};
showModal = () => {
this.setState({ isModalOpen: !this.state.isModalOpen });
};
closeModal = () => {
this.setState({ isModalOpen: false });
};
render() {
return (
<li
onMouseEnter={this.mouseEnter}
onMouseMove={this.mouseEnter}
onMouseLeave={this.mouseExit}
>
<div className="item__row">
<h5>{this.props.name}</h5>
<h6>Age: {this.props.age}</h6>
<p>{this.props.strenght}/100</p>
{this.state.isMouseInside ? (
<button className="btn" onClick={() => this.showForm(false)}>
Change data
</button>
) : null}
</div>
{this.state.isModalOpen ? (
<Modal
onSubmit={this.handleSubmitForm}
/>
) : null}
</li>
);
}
}
What I want to do is to prevent from blocking the possibility of opening two modals or even better if after click on another button in another itemView, opened modal will be closed and suitable will open.
What happened now is I can open multiple modals and everythink works, but I want to make one modal will be displayed on page.
I tried to make another function closeModal which set state of isModalOpen to false before this.setState({ isModalOpen: !this.state.isModalOpen }) in showModal function but it doesn't work.
In this app I use redux and if redux can help solve the problem I can use it.
Visualization what i want to do
CODEPEN EXAMPLE: https://codepen.io/dominik3246/pen/QqKzzp
Upvotes: 1
Views: 2506
Reputation: 3962
Here is how I refactored your code:
currentItemId
currentItemId
matches the current item IDI've tried my utmost to use React's pattern in the refactoring. In fact, I reduced LOC to 59 from 85 and the code IMO looks much neater now.
Use this code as a reference on how can code your React component's and containers in the future as your code needed some polishing.
Codepen: https://codepen.io/metju/pen/LzRqJp
Code:
class List extends React.Component {
constructor() {
super()
this.state = {
currentItemId: undefined,
data: [{id: 0, name: "item1", strenght: 5, age: 5}, {id: 1, name: "item2", strenght: 5, age: 5}, {
id: 2,
name: "item1",
strenght: 5,
age: 5
}, {id: 3, name: "item1", strenght: 5, age: 5}, {id: 4, name: "item1", strenght: 5, age: 5}],
};
this.toggleModalFunc = this.toggleModalFunc.bind(this);
}
toggleModalFunc(id) {
const currentItemId = id !== this.state.currentItemId ? id : undefined
this.setState({ currentItemId })
};
render() {
return (
<ul className="list">
{this.state.data.map((d) => {
return (
<ItemView
key={d.id}
name={d.name}
strenght={d.strenght}
age={d.age}
>
<button className="btn" itemId={d.id} onClick={() => this.toggleModalFunc(d.id)}>
Change data
</button>
{this.state.currentItemId === d.id ? <Modal /> : null}
</ItemView>
);
})}
</ul>
);
}
}
const Modal = () => (
<div>
THIS IS MODAL
</div>
)
const ItemView = (props) => {
return <li>
<div className="item__row">
<h5>{props.name}</h5>
<h6>Age: {props.age}</h6>
<p>{props.strenght}/100</p>
{props.children[0]}
</div>
{props.children[1]}
</li>
}
ReactDOM.render(<List />, document.getElementById('app'));
Upvotes: 2