Reputation: 1691
I got a simple, stateless parent component displaying a list stateful child components. Each individual child component represents a list item whose active state can be toggled (true/false). An active list item becomes green, with close (times) being displayed.
Now, my issue is when one item is selected (active) and I click on another item, both become active, as is expected. However, what I'd like is for the previous item to be deselected/deactivated, such that only one item can be active at a time. I tried lifting state up to the parent and passing it down as props, but this obviously results in every item being active when I click on one item. How do I achieve this?
Below are the code snippets.
import React, { Component } from "react";
class ListItem extends Component {
state = {
isActive: false,
};
onToggleSelect = () =>
this.setState({
isActive: !this.state.isActive,
});
render() {
return (
<li
style={{ color: this.state.isActive && "green", cursor: "pointer" }}
onClick={this.onToggleSelect}
>
Item number {this.props.item}
{this.state.isActive && <span>×</span>}
</li>
);
}
}
function List({ itemList }) {
return (
<div>
<ul>
{
itemList.map(i => <ListItem key={i} item={i} />)
}
</ul>
</div>
);
}
List.defaultProps = {
itemList: [...Array(10).keys()].map(x => x + 1),
};
export default List;
Upvotes: 2
Views: 1732
Reputation: 594
I'd move the click handler up a level:
import React, { useState } from "react";
function ListItem({ item, isActive, handleClick }) {
return (
<li
style={{ color: isActive && "green", cursor: "pointer" }}
onClick={() => handleClick(item)}
>
Item number {item}
{isActive && <span>×</span>}
</li>
);
}
function List({ itemList }) {
const [activeListItem, setActiveListItem] = useState();
const handleClick = (item) => activeListItem === item ? setActiveListItem() : setActiveListItem(item);
return (
<div>
<ul>
{
itemList.map(i => <ListItem key={i} item={i} handleClick={handleClick} isActive={activeListItem === item} />)
}
</ul>
</div>
);
}
Upvotes: 5
Reputation: 57
I think you need to move the state in the parent component to better manage the state of each item.
example with class component
import React, { Component } from "react";
class ListItem extends Component {
render() {
const isActive = this.props.activeIndex === this.props.item;
return (
<li
style={{ color: isActive && "green", cursor: "pointer" }}
onClick={() => this.props.onToggleSelect(this.props.item)}
>
Item number {this.props.item}
{isActive && <span>×</span>}
</li>
);
}
}
class List extends Component {
state = {
activeIndex: null,
};
onToggleSelect = (index) =>
this.setState({
activeIndex: index,
});
return (
<div>
<ul>
{
this.props.itemList.map(i => (
<ListItem
key={i}
activeIndex={this.state.activeIndex}
item={i}
onToggleSelect={onToggleSelect}
/>
))
}
</ul>
</div>
);
}
Upvotes: 0