9
Creating A Memory Game With React
In this article I will explain how I created this Memory Game with React JS
Basically what happens in this game is You will have some cards and when you click on them the card flips and reveals the image that it has. We have to try to find cards in pair(cards with same image).
I have a step by step tutorial for this project on my YouTube channel you can check it out.
But if you just want a overview stick around.
Okay so first I created a Cards.js components. That will render all the cards.
// components/Cards.js
import Card from './Card'
function Cards(){
// Items is a array of objects
// Each object has id, two objects have same id. We will use them to check if the user have found a pair
// They also have a img property. I have put all the images in public/img folder
// Thier stat proprty indicates in what status/state the card is currently on
// stat == "" means the card is not flipped so the image is hidden
// stat == "active" means the card is flipped so the image is visible
// stat == "correct" means we found a pair so the card will be flipped and highlighted in green color
// stat == "wrong" means we choose 2 different type of cards so the card will be flipped and highlighted in red color
const [items, setItems] = useState([
{ id: 1, img: '/img/html.png', stat: "" },
{ id: 1, img: '/img/html.png', stat: "" },
{ id: 2, img: '/img/css.png', stat: "" },
{ id: 2, img: '/img/css.png', stat: "" },
{ id: 3, img: '/img/js.png', stat: "" },
{ id: 3, img: '/img/js.png', stat: "" },
{ id: 4, img: '/img/scss.png', stat: "" },
{ id: 4, img: '/img/scss.png', stat: "" },
{ id: 5, img: '/img/react.png', stat: "" },
{ id: 5, img: '/img/react.png', stat: "" },
{ id: 6, img: '/img/vue.png', stat: "" },
{ id: 6, img: '/img/vue.png', stat: "" },
{ id: 7, img: '/img/angular.png', stat: "" },
{ id: 7, img: '/img/angular.png', stat: "" },
{ id: 8, img: '/img/nodejs.png', stat: "" },
{ id: 8, img: '/img/nodejs.png', stat: "" }
].sort(() => Math.random() - 0.5)) // shuffling the array using the sort method
// This function will be called when the user click on a card
function handleClick(id){
// just for testing
alert(id)
}
return (
<div className="container">
{ items.map((item, index) => (
<Card key={index} item={item} id={index} handleClick={handleClick} />
)) }
</div>
)
}
export default Cards
Then I created the Card.js component.
// components/Card.js
function Card({item, id, handleClick}){
// geting classes based on status of the card
const itemClass = item.stat ? " active " + item.stat : ""
return (
<div className={"card" + itemClass} onClick={() => handleClick(id)}>
<img src={item.img} alt="" />
</div>
)
}
export default Card
And finally I added the JavaScript game logic in Cards.js component
// components/Cards.js
import { useState } from 'react'
import Card from './Card'
function Cards(){
const [items, setItems] = useState([
{ id: 1, img: '/img/html.png', stat: "" },
{ id: 1, img: '/img/html.png', stat: "" },
{ id: 2, img: '/img/css.png', stat: "" },
{ id: 2, img: '/img/css.png', stat: "" },
{ id: 3, img: '/img/js.png', stat: "" },
{ id: 3, img: '/img/js.png', stat: "" },
{ id: 4, img: '/img/scss.png', stat: "" },
{ id: 4, img: '/img/scss.png', stat: "" },
{ id: 5, img: '/img/react.png', stat: "" },
{ id: 5, img: '/img/react.png', stat: "" },
{ id: 6, img: '/img/vue.png', stat: "" },
{ id: 6, img: '/img/vue.png', stat: "" },
{ id: 7, img: '/img/angular.png', stat: "" },
{ id: 7, img: '/img/angular.png', stat: "" },
{ id: 8, img: '/img/nodejs.png', stat: "" },
{ id: 8, img: '/img/nodejs.png', stat: "" }
].sort(() => Math.random() - 0.5))
// prev is short for previous
// prev will store the id of previously clicked card
const [prev, setPrev] = useState(-1)
function check(current){
if(items[current].id == items[prev].id){
// if previously clicked card is same as current card
// set the stat of both cards to correct
items[current].stat = "correct"
items[prev].stat = "correct"
setItems([...items])
setPrev(-1)
}else{
// if previously clicked card is same not as current card
// set the stat of both cards to wrong
items[current].stat = "wrong"
items[prev].stat = "wrong"
setItems([...items])
// After 1 second, set the stat of both cards to ""
// So they would flip back
setTimeout(() => {
items[current].stat = ""
items[prev].stat = ""
setItems([...items])
setPrev(-1)
}, 1000)
}
}
function handleClick(id){
if(prev === -1){ // if prev is -1, then it means no card was clicked previously.
items[id].stat = "active"
setItems([...items])
setPrev(id)
}else{
check(id)
}
}
return (
<div className="container">
{ items.map((item, index) => (
<Card key={index} item={item} id={index} handleClick={handleClick} />
)) }
</div>
)
}
export default Cards
you can find the complete coded here.
Make sure you checkout my other articles and YouTube channel
9