Reputation: 163
I'm slowly getting the knack (I think) for react. What I'm trying to do is display a list in one component and then make each list item (item 1, item 2, etc..) clickable so that when it is clicked, it can move back and forth between the two <ItemList />
components. What I have is below, I think where my problem is setting the state on the first list in the handleEvent()
.
class SingleItem extends React.Component {
render() {
let data = this.props.data;
return (
<li>
<div> {data.name} </div>
</li>
);
}
}
class ItemList extends React.Component {
render() {
let itemArr = this.props.items;
let listItems = itemArr.map((itemObj) => {
return <SingleItem key={itemObj.id} data={itemObj}/>;
});
return (
<ul onClick={props.handleEvent}>
{listItems}
</ul>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
boxOne: {listItems},
boxTwo:''
};
this.handleEvent = this.handleEvent.bind(this);
}
handleEvent() {
this.setState({
boxOne: this.state.boxTwo,
boxTwo: this.state.boxOne
});
}
render() {
return (
<div>
<ItemList items={this.state.boxOne} />
<ItemList items={this.state.boxTwo} />
</div>
);
}
};
var items = [
{name: "Item 1", id: 1},
{name: "Item 2", id: 2},
{name: "Item 3", id: 3},
{name: "Item 4", id: 4},
]
ReactDOM.render(<App />, document.getElementById('root'));
Upvotes: 1
Views: 7843
Reputation: 13211
This is how it could be done..
So, I am passing the whole items array to all ItemLists, but I am also passing the state, which is just an array with ids of the included items in that list, check out the logic below and try to understand, it's easy actually..
class SingleItem extends React.Component {
render() {
let data = this.props.data;
return (
<li onClick={this.props.onClick}>
<div> {data.name} </div>
</li>
);
}
}
class ItemList extends React.Component {
render() {
let itemArr = this.props.allItems;
let myItems = this.props.items;
let handleEvent = this.props.handleEvent;
let listItems = itemArr.map((itemObj) => {
if (!myItems.includes(itemObj.id)) return null;
return <SingleItem
key={itemObj.id}
data={itemObj}
onClick={() => handleEvent(itemObj.id)}
/>;
});
return (
<ul>
{listItems}
</ul>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
boxOne: props.items.map(item => item.id), // init the boxes with itemIds
boxTwo: []
};
this.handleEvent = this.handleEvent.bind(this);
}
handleEvent(itemId) {
const isInBoxOne = this.state.boxOne.includes(itemId);
// Heres the magic, if the item is in the first Box, filter it out,
// and put into the second, otherwise the other way around..
this.setState({
boxOne: isInBoxOne
? this.state.boxOne.filter(i => i !== itemId)
: [ ...this.state.boxOne, itemId ]
boxTwo: isInBoxOne
? [ ...this.state.boxTwo, itemId ]
: this.state.boxTwo.filter(i => i !== itemId)
});
}
render() {
return (
<div>
<ItemList handleEvent={this.handleEvent} items={this.state.boxOne} allItems={this.props.items} />
<ItemList handleEvent={this.handleEvent} items={this.state.boxTwo} allItems={this.props.items} />
</div>
);
}
};
var items = [
{name: "Item 1", id: 1},
{name: "Item 2", id: 2},
{name: "Item 3", id: 3},
{name: "Item 4", id: 4},
]
ReactDOM.render(
// Pass the initial items to your App
<App items={items} />,
document.getElementById('root')
);
Upvotes: 3