I am creating a Reactjs card memory game. The idea is that you need to click on a card and match it with an identical one. I have the flip animations working, but my issue is with state. When I click on 1 card, all of them flip instead of 1. Hopefully someone can shed some light on this. Thank you,
App.js
class App extends Component {
constructor(props) {
super(props);
this.state = {
isFlipped: false,
visible: false,
}
}
componentDidMount() {
this.setState({ visible: true });
}
toggleClass = () => {
this.setState(
(prevState) => {
console.log(prevState); // refers to previous state
return {
isFlipped: !prevState.isFlipped,
};
},
() => console.log(this.state)
) // refers to updated state
}
render() {
return (
<>
<h3>Welcome!!</h3>
<div className="cards-container">
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
<Card
isFlipped={this.state.isFlipped}
visible={this.state.visible}
toggleClass={ this.toggleClass }
/>
</div>
</>
);
}
}
Card.js
class Card extends Component {
render() {
const { isFlipped, visible, toggleClass } = this.props
render() {
const { isFlipped, visible, toggleClass } = this.props
return (
<div className={visible ? "fade-in scene" : "scene"}>
<div
className={isFlipped ? "card is-flipped" : "card"}
onClick={toggleClass}
>
<div className="card__face card__face--front"></div>
<div className="card__face card__face--back">
<FontAwesomeIcon
icon={ faOtter }
color="coral"
size="2x"
/>
</div>
</div>
</div>
)
}
}
App.css
body {
font-family: sans-serif;
background-image: linear-gradient(rgba(0, 0, 0, 0.883), rgba(0, 0, 0, 0.103)), url(../assets/imgs/wood.jpg);
width: 100%;
height: 100vh;
background-size: cover;
background-position: center;
top:0px; bottom: 0px;
/* height: 100%; */
background-repeat: repeat;
}
.scene {
width: 100px;
height: 130px;
perspective: 600px;
position: relative;
margin: 5px;
box-shadow: 1em 1em 2em rgba(0, 0, 0, 0.945);
border-radius: 10px;
}
/* Animate flip when cards are clicked */
.card {
cursor: pointer;
position: relative;
width: 100%;
height: 100%;
transition: transform 1.3s;
transform-style: preserve-3d;
}
.card.is-flipped {
transform: rotateY(180deg);
}
.card__face {
position: absolute;
width: 100%;
height: 100%;
line-height: 145px;
text-align: center;
border-radius: 10px;
}
.card__face--front {
background-image: linear-gradient(to bottom, #070809, #0a0a0f, #120a11, #180b0e, #1c0d06);
}
.card__face--back {
background-image: linear-gradient(to bottom, #070809, #0a0a0f, #120a11, #180b0e, #1c0d06);
transform: rotateY(180deg);
}
/* centering cards container and flexing cards inside */
.cards-container {
width: 600px;
height: 200px;
position: absolute;
left: 30%;
top: 30%;
margin: -100px 0 0 -150px;
display: flex;
flex-wrap: wrap;
}
/* Animations */
@keyframes wiggle {
0% { transform: rotate(0deg); }
80% { transform: rotate(0deg); }
85% { transform: rotate(5deg); }
95% { transform: rotate(-5deg); }
100% { transform: rotate(0deg); }
}
.fade-in {
display: inline-block;
animation: wiggle 3s infinite;
}
.fade-in:hover {
animation: none;
}
/* Font Awesome Icons */
i {
color: #fff;
}