I am new to React and am trying to build an app in which a user can create a card, delete a card, and change the order of the cards array by clicking left or right arrow to switch elements with the element on the left or on the right. I am struggling to code this functionaliy. I have the function written to switch the card with that on the left, but this function is not doing anything right now. I also do not get any errors in the console from this function, so I really cannot determine where I am going wrong here. Here is the code so far:
CardList.js will display the form to add a card and display the array of CardItems, passing the functions to switch these items to the left or right ('moveLeft', 'moveRight') as props.
import React from "react";
import CardItem from "./CardItem";
import CardForm from "./CardForm";
import './Card.css';
class CardList extends React.Component {
state = {
cards: JSON.parse(localStorage.getItem(`cards`)) || []
// when the component mounts, read from localStorage and set/initialize the state
};
componentDidUpdate(prevProps, prevState) { // persist state changes to longer term storage when it's updated
localStorage.setItem(
`cards`,
JSON.stringify(this.state.cards)
);
}
render() {
const cards = this.getCards();
const cardNodes = (
<div style={{ display: 'flex' }}>{cards}</div>
);
return (
<div>
<CardForm addCard={this.addCard.bind(this)} />
<div className="container">
<div className="card-collection">
{cardNodes}
</div>
</div>
</div>
);
}
addCard(name) {
const card = {
name
};
this.setState({
cards: this.state.cards.concat([card])
}); // new array references help React stay fast, so concat works better than push here.
}
removeCard(index) {
this.state.cards.splice(index, 1)
this.setState({
cards: this.state.cards.filter(i => i !== index)
})
}
moveLeft(index,card) {
if (index > 1) {
this.state.cards.splice(index, 1);
this.state.cards.splice((index !== 0) ? index - 1 : this.state.cards.length, 0, card)
}
return this.state.cards
}
moveRight(index, card) {
// ?
}
getCards() {
return this.state.cards.map((card) => {
return (
<CardItem
card={card}
index={card.index}
name={card.name}
removeCard={this.removeCard.bind(this)}
moveLeft={this.moveLeft.bind(this)}
moveRight={this.moveRight.bind(this)}
/>
);
});
}
}
export default CardList;
CardItem is taking in those props and ideally handling moving the card left or right in the array once the left or right icon is clicked.
import React from 'react';
import Card from "react-bootstrap/Card";
import Button from "react-bootstrap/Button";
class CardItem extends React.Component {
render() {
return (
<div>
<Card style={{ width: '15rem'}}>
<Card.Header as="h5">{this.props.name}</Card.Header>
<Card.Body>
<Button variant="primary" onClick={this.handleClick.bind(this)}>Remove</Button>
</Card.Body>
<Card.Footer style={{ display: 'flex' }}>
<i class="arrow left icon" onClick={this.leftClick.bind(this)} style={{ color: 'blue'}}></i>
<i class="arrow right icon" onClick={this.rightClick.bind(this)} style={{ color: 'blue'}}></i>
</Card.Footer>
</Card>
</div>
)
}
handleClick(index) {
this.props.removeCard(index)
}
leftClick(index, card) {
this.props.moveLeft(index, card)
}
rightClick(index, card) {
this.props.moveRight(index, card)
}
}
export default CardItem;
Not sure where I am going wrong here. Any help would be appreciated
Edit #1 Hey guys, so I wrote out a different function to handle moving the card to the left, and I decided to bind "this" to that method in the constructor because I was getting errors saying the program could not read it. However, I am still getting errors basically saying that everything is not defined when I pass the function from CardList to CardItem as props. Does anybody know what the problem is? I suspect its my syntax when I call the methods in CardItem.
CardList.js
import React from "react";
import CardItem from "./CardItem";
import CardForm from "./CardForm";
import './Card.css';
class CardList extends React.Component {
constructor(props) {
super();
this.moveLeft = this.moveLeft.bind(this);
this.moveRight = this.moveRight.bind(this);
this.state = {
cards: JSON.parse(localStorage.getItem(`cards`)) || []
// when the component mounts, read from localStorage and set/initialize the state
};
}
componentDidUpdate(prevProps, prevState) { // persist state changes to longer term storage when it's updated
localStorage.setItem(
`cards`,
JSON.stringify(this.state.cards)
);
}
render() {
const cards = this.getCards();
const cardNodes = (
<div style={{ display: 'flex' }}>{cards}</div>
);
return (
<div>
<CardForm addCard={this.addCard.bind(this)} />
<div className="container">
<div className="card-collection">
{cardNodes}
</div>
</div>
</div>
);
}
addCard(name) {
const card = {
name
};
this.setState({
cards: this.state.cards.concat([card])
}); // new array references help React stay fast, so concat works better than push here.
}
removeCard(index) {
this.state.cards.splice(index, 1)
this.setState({
cards: this.state.cards.filter(i => i !== index)
})
}
moveLeft(index, card) {
this.setState((prevState, prevProps) => {
return {cards: prevState.cards.map(( c, i)=> {
// also handle case when index == 0
if (i === index) {
return prevState.cards[index - 1];
} else if (i === index - 1) {
return prevState.cards[index];
}
})};
});
}
moveRight(index, card) {
// ?
}
getCards() {
return this.state.cards.map((card) => {
return (
<CardItem
card={card}
index={card.index}
name={card.name}
removeCard={this.removeCard.bind(this)}
moveLeft={this.moveLeft}
moveRight={this.moveRight}
/>
);
});
}
}
export default CardList;
CardItem.js
import React from 'react';
import Card from "react-bootstrap/Card";
import Button from "react-bootstrap/Button";
class CardItem extends React.Component {
render() {
return (
<div>
<Card style={{ width: '15rem'}}>
<Card.Header as="h5">{this.props.name}</Card.Header>
<Card.Body>
<Button variant="primary" onClick={this.handleClick.bind(this)}>Remove</Button>
</Card.Body>
<Card.Footer style={{ display: 'flex' }}>
<i class="arrow left icon" onClick={leftClick(index, card)} style={{ color: 'blue'}}></i>
<i class="arrow right icon" onClick={rightClick(index, card)} style={{ color: 'blue'}}></i>
</Card.Footer>
</Card>
</div>
)
}
handleClick(index) {
this.props.removeCard(index)
}
leftClick(index, card) {
this.props.moveLeft(index,card)
}
rightClick(index, card) {
this.props.moveRight(index, card)
}
}
export default CardItem;