Memory Game in React
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
1
down vote
favorite
This is my second game in React (I posted a country guessing game 2 days ago). Please review my code.
Preview
Alert: May work only in Google Chrome (I build here)
import React, Component from 'react';
import './MemoryGame.css';
class MemoryGame extends Component
constructor(props)
super(props);
//Array of memory images
this.ImagePieces = ['cat', 'cat', 'dog', 'dog', 'horse', 'horse',
'pig', 'pig', 'snake', 'snake', 'fish', 'fish'];
this.tempCheckArr = ;
this.state =
showImg: Array(this.ImagePieces.length).fill('hidden'),
divClick: true,
compareImgArr: ,
counter: 0
this.checkMatch = this.checkMatch.bind(this);
//Shuffle memory game images
componentWillMount()
function shuffleArray(array)
for (let i = array.length - 1; i > 0; i--)
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
return array;
shuffleArray(this.ImagePieces);
//Check for match function
checkMatch(key, e)
//For later hidding images purposes
this.tempCheckArr.push(key.toString());
//Create copy of (compareImgArr) and add img src, for later compare
const imgSrc = e.target.firstChild.src;
const compareImgArr = [...this.state.compareImgArr];
compareImgArr.push(imgSrc);
//Set current clicked item as 'visible' in main array 'showImg'
const arr = this.state.showImg
arr[key] = 'visible';
//Update state, counter for block user click method
//after unhidding two pieces
this.setState(
showImg: arr,
compareImgArr: compareImgArr,
counter: this.state.counter + 1
);
//Check if 2 items are clicked - if yes - disable clicking
if (this.state.counter % 2)
this.setState(
divClick: false
);
//Check if pictures are matching
if (compareImgArr[0] === compareImgArr[1])
this.tempCheckArr = ;
this.setState(
compareImgArr: ,
divClick: true
);
else
//If pictures not match turn them back to hidden
var tempArr = this.state.showImg
// eslint-disable-next-line
var firstElement = parseInt(this.tempCheckArr[0]);
// eslint-disable-next-line
var secondElement = parseInt(this.tempCheckArr[1]);
setTimeout(()=>
tempArr[firstElement] = 'hidden';
tempArr[secondElement] = 'hidden';
this.tempCheckArr = ;
this.setState(
showImg: tempArr,
compareImgArr: ,
divClick: true
)
, 1500)
render()
return(
<div>
<h1>Memory Game</h1>
<div className="mui-panel wrapper">
this.ImagePieces.map((text, i) =>
return (
<div key=i className="modal mui-panel"
onClick=this.state.divClick ? (e) => this.checkMatch(i, e) : undefined>
<img style=visibility: this.state.showImg[i] src='./'+text+'.jpg'
srcSet='./'+text+'_lrg.jpg 1000w' key=i alt="Game Element"/>
</div>
)
)
</div>
</div>
)
export default MemoryGame;
react.js jsx
add a comment |Â
up vote
1
down vote
favorite
This is my second game in React (I posted a country guessing game 2 days ago). Please review my code.
Preview
Alert: May work only in Google Chrome (I build here)
import React, Component from 'react';
import './MemoryGame.css';
class MemoryGame extends Component
constructor(props)
super(props);
//Array of memory images
this.ImagePieces = ['cat', 'cat', 'dog', 'dog', 'horse', 'horse',
'pig', 'pig', 'snake', 'snake', 'fish', 'fish'];
this.tempCheckArr = ;
this.state =
showImg: Array(this.ImagePieces.length).fill('hidden'),
divClick: true,
compareImgArr: ,
counter: 0
this.checkMatch = this.checkMatch.bind(this);
//Shuffle memory game images
componentWillMount()
function shuffleArray(array)
for (let i = array.length - 1; i > 0; i--)
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
return array;
shuffleArray(this.ImagePieces);
//Check for match function
checkMatch(key, e)
//For later hidding images purposes
this.tempCheckArr.push(key.toString());
//Create copy of (compareImgArr) and add img src, for later compare
const imgSrc = e.target.firstChild.src;
const compareImgArr = [...this.state.compareImgArr];
compareImgArr.push(imgSrc);
//Set current clicked item as 'visible' in main array 'showImg'
const arr = this.state.showImg
arr[key] = 'visible';
//Update state, counter for block user click method
//after unhidding two pieces
this.setState(
showImg: arr,
compareImgArr: compareImgArr,
counter: this.state.counter + 1
);
//Check if 2 items are clicked - if yes - disable clicking
if (this.state.counter % 2)
this.setState(
divClick: false
);
//Check if pictures are matching
if (compareImgArr[0] === compareImgArr[1])
this.tempCheckArr = ;
this.setState(
compareImgArr: ,
divClick: true
);
else
//If pictures not match turn them back to hidden
var tempArr = this.state.showImg
// eslint-disable-next-line
var firstElement = parseInt(this.tempCheckArr[0]);
// eslint-disable-next-line
var secondElement = parseInt(this.tempCheckArr[1]);
setTimeout(()=>
tempArr[firstElement] = 'hidden';
tempArr[secondElement] = 'hidden';
this.tempCheckArr = ;
this.setState(
showImg: tempArr,
compareImgArr: ,
divClick: true
)
, 1500)
render()
return(
<div>
<h1>Memory Game</h1>
<div className="mui-panel wrapper">
this.ImagePieces.map((text, i) =>
return (
<div key=i className="modal mui-panel"
onClick=this.state.divClick ? (e) => this.checkMatch(i, e) : undefined>
<img style=visibility: this.state.showImg[i] src='./'+text+'.jpg'
srcSet='./'+text+'_lrg.jpg 1000w' key=i alt="Game Element"/>
</div>
)
)
</div>
</div>
)
export default MemoryGame;
react.js jsx
add a comment |Â
up vote
1
down vote
favorite
up vote
1
down vote
favorite
This is my second game in React (I posted a country guessing game 2 days ago). Please review my code.
Preview
Alert: May work only in Google Chrome (I build here)
import React, Component from 'react';
import './MemoryGame.css';
class MemoryGame extends Component
constructor(props)
super(props);
//Array of memory images
this.ImagePieces = ['cat', 'cat', 'dog', 'dog', 'horse', 'horse',
'pig', 'pig', 'snake', 'snake', 'fish', 'fish'];
this.tempCheckArr = ;
this.state =
showImg: Array(this.ImagePieces.length).fill('hidden'),
divClick: true,
compareImgArr: ,
counter: 0
this.checkMatch = this.checkMatch.bind(this);
//Shuffle memory game images
componentWillMount()
function shuffleArray(array)
for (let i = array.length - 1; i > 0; i--)
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
return array;
shuffleArray(this.ImagePieces);
//Check for match function
checkMatch(key, e)
//For later hidding images purposes
this.tempCheckArr.push(key.toString());
//Create copy of (compareImgArr) and add img src, for later compare
const imgSrc = e.target.firstChild.src;
const compareImgArr = [...this.state.compareImgArr];
compareImgArr.push(imgSrc);
//Set current clicked item as 'visible' in main array 'showImg'
const arr = this.state.showImg
arr[key] = 'visible';
//Update state, counter for block user click method
//after unhidding two pieces
this.setState(
showImg: arr,
compareImgArr: compareImgArr,
counter: this.state.counter + 1
);
//Check if 2 items are clicked - if yes - disable clicking
if (this.state.counter % 2)
this.setState(
divClick: false
);
//Check if pictures are matching
if (compareImgArr[0] === compareImgArr[1])
this.tempCheckArr = ;
this.setState(
compareImgArr: ,
divClick: true
);
else
//If pictures not match turn them back to hidden
var tempArr = this.state.showImg
// eslint-disable-next-line
var firstElement = parseInt(this.tempCheckArr[0]);
// eslint-disable-next-line
var secondElement = parseInt(this.tempCheckArr[1]);
setTimeout(()=>
tempArr[firstElement] = 'hidden';
tempArr[secondElement] = 'hidden';
this.tempCheckArr = ;
this.setState(
showImg: tempArr,
compareImgArr: ,
divClick: true
)
, 1500)
render()
return(
<div>
<h1>Memory Game</h1>
<div className="mui-panel wrapper">
this.ImagePieces.map((text, i) =>
return (
<div key=i className="modal mui-panel"
onClick=this.state.divClick ? (e) => this.checkMatch(i, e) : undefined>
<img style=visibility: this.state.showImg[i] src='./'+text+'.jpg'
srcSet='./'+text+'_lrg.jpg 1000w' key=i alt="Game Element"/>
</div>
)
)
</div>
</div>
)
export default MemoryGame;
react.js jsx
This is my second game in React (I posted a country guessing game 2 days ago). Please review my code.
Preview
Alert: May work only in Google Chrome (I build here)
import React, Component from 'react';
import './MemoryGame.css';
class MemoryGame extends Component
constructor(props)
super(props);
//Array of memory images
this.ImagePieces = ['cat', 'cat', 'dog', 'dog', 'horse', 'horse',
'pig', 'pig', 'snake', 'snake', 'fish', 'fish'];
this.tempCheckArr = ;
this.state =
showImg: Array(this.ImagePieces.length).fill('hidden'),
divClick: true,
compareImgArr: ,
counter: 0
this.checkMatch = this.checkMatch.bind(this);
//Shuffle memory game images
componentWillMount()
function shuffleArray(array)
for (let i = array.length - 1; i > 0; i--)
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
return array;
shuffleArray(this.ImagePieces);
//Check for match function
checkMatch(key, e)
//For later hidding images purposes
this.tempCheckArr.push(key.toString());
//Create copy of (compareImgArr) and add img src, for later compare
const imgSrc = e.target.firstChild.src;
const compareImgArr = [...this.state.compareImgArr];
compareImgArr.push(imgSrc);
//Set current clicked item as 'visible' in main array 'showImg'
const arr = this.state.showImg
arr[key] = 'visible';
//Update state, counter for block user click method
//after unhidding two pieces
this.setState(
showImg: arr,
compareImgArr: compareImgArr,
counter: this.state.counter + 1
);
//Check if 2 items are clicked - if yes - disable clicking
if (this.state.counter % 2)
this.setState(
divClick: false
);
//Check if pictures are matching
if (compareImgArr[0] === compareImgArr[1])
this.tempCheckArr = ;
this.setState(
compareImgArr: ,
divClick: true
);
else
//If pictures not match turn them back to hidden
var tempArr = this.state.showImg
// eslint-disable-next-line
var firstElement = parseInt(this.tempCheckArr[0]);
// eslint-disable-next-line
var secondElement = parseInt(this.tempCheckArr[1]);
setTimeout(()=>
tempArr[firstElement] = 'hidden';
tempArr[secondElement] = 'hidden';
this.tempCheckArr = ;
this.setState(
showImg: tempArr,
compareImgArr: ,
divClick: true
)
, 1500)
render()
return(
<div>
<h1>Memory Game</h1>
<div className="mui-panel wrapper">
this.ImagePieces.map((text, i) =>
return (
<div key=i className="modal mui-panel"
onClick=this.state.divClick ? (e) => this.checkMatch(i, e) : undefined>
<img style=visibility: this.state.showImg[i] src='./'+text+'.jpg'
srcSet='./'+text+'_lrg.jpg 1000w' key=i alt="Game Element"/>
</div>
)
)
</div>
</div>
)
export default MemoryGame;
react.js jsx
edited Jan 21 at 21:07
200_success
123k14143401
123k14143401
asked Jan 6 at 22:50
Franky
465
465
add a comment |Â
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
1
down vote
Ok, I had quite a few thoughts on this.
State
Your state seems more complex than it needs to be, and some of it is hiding outside of the state
variable.
I think all you really need to keep track of are:
- What order the images are in
- Which images are currently selected
- Which images have been guessed correctly
I don't really understand what tempCheckArr
is, how it's different from compareImgArr
, or why it's an instance variable.
Extract stuff
I think you have too much stuff crammed into one component.
I think you need to extract pieces of logic that can be self contained.
Prime example: shuffleArray
Why is shuffleArray
declared inside componentWillMount
?
This is creating a new shuffleArray
function every time MemoryGame
is mounted.
I think shuffleArray
should at least be outside of this component, and really should be in a some sort of RandomUtil.js
file.
Card component
I would also extract out a Card component that renders a card.
It should know:
- What image to display
- Whether or not it's selected
- Whether or not it's been guessed correctly
This way you can keep your MemoryGame component about managing the state of the game while the Card component focuses on presentation.
Other Thoughts
- Your
<img>
tag doesn't need akey
prop because it's not the top level thing in an array. - Why is
ImagePieces
declared onthis
. It seems like it should be part of state. - (Also why is the
I
inImagePieces
uppercase? It seems like this should beimagePieces
) - Why are you shuffling ImagePieces in componentWillMount and not just in the constructor?
- It's kinda gross to reach into the DOM to compare the elements
src
attribute, and it makes it harder to understand what you actually want to compare: that the two images selected are of the same thing - Why are you converting integers to strings when you put them into
tempCheckArr
and converting them back when you take them out? Wouldn't it be easier to just put integers into the array?
How I would write it
const IMAGES = ["cat", "cat", "dog", "dog", "horse", "horse", "pig",
"pig", "snake", "snake", "fish", "fish"];
class MemoryGame extends Component
constructor(props)
super(props);
// You can simplify your state a lot
this.state =
cards: shuffleArray(IMAGES.slice()),
selected: , // indexes which have been selected
correct: // indexes which have been guessed correctly
;
// Don't need a componentWillMount
onCardClick(clickedIndex)
const selected, cards, correct = this.state;
if (selected.length === 0) // selecting a first card
this.setState( selected: [clickedIndex] )
else if (selected.length === 1) // they're selecting a second card
if (cards[selected[0]] === cards[clickedIndex])
// It's a match :)
// Add selected cards to `correct` and reset selection
this.setState(
correct: correct.concat([selected[0], clickedIndex]),
selected:
);
else
// It's not a match :(
// Select it for now, and reset selection in a bit
this.setState( selected: [selected[0], clickedIndex] );
setTimeout(() =>
this.setState( selected: )
, 1500);
// Otherwise they already have 2 selected and we don't wanna do anything
render()
const correct, selected, cards = this.state;
return (
<div>
<h1>Memory Game</h1>
<div className="mui-panel wrapper">
cards.map((image, i) => (
<MemoryCard
key=i
image=image
isCorrect=correct.includes(i)
isSelected=selected.includes(i)
onSelect=() => this.onCardClick(i)
/>
))
</div>
</div>
);
// Extracted into it's own component
const MemoryCard = ( image, isSelected, isCorrect, onSelect ) => (
<div
className="modal mui-panel"
onClick=() =>
// You can only select a card that's not already correct and
// isn't currently selected
if (!isCorrect && !isSelected)
onSelect();
>
<img
style=
src="./" + image + ".jpg"
srcSet="./" + image + "_lrg.jpg 1000w"
alt=image
/>
</div>
);
// Probably in a different file
function shuffleArray(array)
for (let i = array.length - 1; i > 0; i--)
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
return array;
export default MemoryGame;
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
Ok, I had quite a few thoughts on this.
State
Your state seems more complex than it needs to be, and some of it is hiding outside of the state
variable.
I think all you really need to keep track of are:
- What order the images are in
- Which images are currently selected
- Which images have been guessed correctly
I don't really understand what tempCheckArr
is, how it's different from compareImgArr
, or why it's an instance variable.
Extract stuff
I think you have too much stuff crammed into one component.
I think you need to extract pieces of logic that can be self contained.
Prime example: shuffleArray
Why is shuffleArray
declared inside componentWillMount
?
This is creating a new shuffleArray
function every time MemoryGame
is mounted.
I think shuffleArray
should at least be outside of this component, and really should be in a some sort of RandomUtil.js
file.
Card component
I would also extract out a Card component that renders a card.
It should know:
- What image to display
- Whether or not it's selected
- Whether or not it's been guessed correctly
This way you can keep your MemoryGame component about managing the state of the game while the Card component focuses on presentation.
Other Thoughts
- Your
<img>
tag doesn't need akey
prop because it's not the top level thing in an array. - Why is
ImagePieces
declared onthis
. It seems like it should be part of state. - (Also why is the
I
inImagePieces
uppercase? It seems like this should beimagePieces
) - Why are you shuffling ImagePieces in componentWillMount and not just in the constructor?
- It's kinda gross to reach into the DOM to compare the elements
src
attribute, and it makes it harder to understand what you actually want to compare: that the two images selected are of the same thing - Why are you converting integers to strings when you put them into
tempCheckArr
and converting them back when you take them out? Wouldn't it be easier to just put integers into the array?
How I would write it
const IMAGES = ["cat", "cat", "dog", "dog", "horse", "horse", "pig",
"pig", "snake", "snake", "fish", "fish"];
class MemoryGame extends Component
constructor(props)
super(props);
// You can simplify your state a lot
this.state =
cards: shuffleArray(IMAGES.slice()),
selected: , // indexes which have been selected
correct: // indexes which have been guessed correctly
;
// Don't need a componentWillMount
onCardClick(clickedIndex)
const selected, cards, correct = this.state;
if (selected.length === 0) // selecting a first card
this.setState( selected: [clickedIndex] )
else if (selected.length === 1) // they're selecting a second card
if (cards[selected[0]] === cards[clickedIndex])
// It's a match :)
// Add selected cards to `correct` and reset selection
this.setState(
correct: correct.concat([selected[0], clickedIndex]),
selected:
);
else
// It's not a match :(
// Select it for now, and reset selection in a bit
this.setState( selected: [selected[0], clickedIndex] );
setTimeout(() =>
this.setState( selected: )
, 1500);
// Otherwise they already have 2 selected and we don't wanna do anything
render()
const correct, selected, cards = this.state;
return (
<div>
<h1>Memory Game</h1>
<div className="mui-panel wrapper">
cards.map((image, i) => (
<MemoryCard
key=i
image=image
isCorrect=correct.includes(i)
isSelected=selected.includes(i)
onSelect=() => this.onCardClick(i)
/>
))
</div>
</div>
);
// Extracted into it's own component
const MemoryCard = ( image, isSelected, isCorrect, onSelect ) => (
<div
className="modal mui-panel"
onClick=() =>
// You can only select a card that's not already correct and
// isn't currently selected
if (!isCorrect && !isSelected)
onSelect();
>
<img
style=
src="./" + image + ".jpg"
srcSet="./" + image + "_lrg.jpg 1000w"
alt=image
/>
</div>
);
// Probably in a different file
function shuffleArray(array)
for (let i = array.length - 1; i > 0; i--)
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
return array;
export default MemoryGame;
add a comment |Â
up vote
1
down vote
Ok, I had quite a few thoughts on this.
State
Your state seems more complex than it needs to be, and some of it is hiding outside of the state
variable.
I think all you really need to keep track of are:
- What order the images are in
- Which images are currently selected
- Which images have been guessed correctly
I don't really understand what tempCheckArr
is, how it's different from compareImgArr
, or why it's an instance variable.
Extract stuff
I think you have too much stuff crammed into one component.
I think you need to extract pieces of logic that can be self contained.
Prime example: shuffleArray
Why is shuffleArray
declared inside componentWillMount
?
This is creating a new shuffleArray
function every time MemoryGame
is mounted.
I think shuffleArray
should at least be outside of this component, and really should be in a some sort of RandomUtil.js
file.
Card component
I would also extract out a Card component that renders a card.
It should know:
- What image to display
- Whether or not it's selected
- Whether or not it's been guessed correctly
This way you can keep your MemoryGame component about managing the state of the game while the Card component focuses on presentation.
Other Thoughts
- Your
<img>
tag doesn't need akey
prop because it's not the top level thing in an array. - Why is
ImagePieces
declared onthis
. It seems like it should be part of state. - (Also why is the
I
inImagePieces
uppercase? It seems like this should beimagePieces
) - Why are you shuffling ImagePieces in componentWillMount and not just in the constructor?
- It's kinda gross to reach into the DOM to compare the elements
src
attribute, and it makes it harder to understand what you actually want to compare: that the two images selected are of the same thing - Why are you converting integers to strings when you put them into
tempCheckArr
and converting them back when you take them out? Wouldn't it be easier to just put integers into the array?
How I would write it
const IMAGES = ["cat", "cat", "dog", "dog", "horse", "horse", "pig",
"pig", "snake", "snake", "fish", "fish"];
class MemoryGame extends Component
constructor(props)
super(props);
// You can simplify your state a lot
this.state =
cards: shuffleArray(IMAGES.slice()),
selected: , // indexes which have been selected
correct: // indexes which have been guessed correctly
;
// Don't need a componentWillMount
onCardClick(clickedIndex)
const selected, cards, correct = this.state;
if (selected.length === 0) // selecting a first card
this.setState( selected: [clickedIndex] )
else if (selected.length === 1) // they're selecting a second card
if (cards[selected[0]] === cards[clickedIndex])
// It's a match :)
// Add selected cards to `correct` and reset selection
this.setState(
correct: correct.concat([selected[0], clickedIndex]),
selected:
);
else
// It's not a match :(
// Select it for now, and reset selection in a bit
this.setState( selected: [selected[0], clickedIndex] );
setTimeout(() =>
this.setState( selected: )
, 1500);
// Otherwise they already have 2 selected and we don't wanna do anything
render()
const correct, selected, cards = this.state;
return (
<div>
<h1>Memory Game</h1>
<div className="mui-panel wrapper">
cards.map((image, i) => (
<MemoryCard
key=i
image=image
isCorrect=correct.includes(i)
isSelected=selected.includes(i)
onSelect=() => this.onCardClick(i)
/>
))
</div>
</div>
);
// Extracted into it's own component
const MemoryCard = ( image, isSelected, isCorrect, onSelect ) => (
<div
className="modal mui-panel"
onClick=() =>
// You can only select a card that's not already correct and
// isn't currently selected
if (!isCorrect && !isSelected)
onSelect();
>
<img
style=
src="./" + image + ".jpg"
srcSet="./" + image + "_lrg.jpg 1000w"
alt=image
/>
</div>
);
// Probably in a different file
function shuffleArray(array)
for (let i = array.length - 1; i > 0; i--)
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
return array;
export default MemoryGame;
add a comment |Â
up vote
1
down vote
up vote
1
down vote
Ok, I had quite a few thoughts on this.
State
Your state seems more complex than it needs to be, and some of it is hiding outside of the state
variable.
I think all you really need to keep track of are:
- What order the images are in
- Which images are currently selected
- Which images have been guessed correctly
I don't really understand what tempCheckArr
is, how it's different from compareImgArr
, or why it's an instance variable.
Extract stuff
I think you have too much stuff crammed into one component.
I think you need to extract pieces of logic that can be self contained.
Prime example: shuffleArray
Why is shuffleArray
declared inside componentWillMount
?
This is creating a new shuffleArray
function every time MemoryGame
is mounted.
I think shuffleArray
should at least be outside of this component, and really should be in a some sort of RandomUtil.js
file.
Card component
I would also extract out a Card component that renders a card.
It should know:
- What image to display
- Whether or not it's selected
- Whether or not it's been guessed correctly
This way you can keep your MemoryGame component about managing the state of the game while the Card component focuses on presentation.
Other Thoughts
- Your
<img>
tag doesn't need akey
prop because it's not the top level thing in an array. - Why is
ImagePieces
declared onthis
. It seems like it should be part of state. - (Also why is the
I
inImagePieces
uppercase? It seems like this should beimagePieces
) - Why are you shuffling ImagePieces in componentWillMount and not just in the constructor?
- It's kinda gross to reach into the DOM to compare the elements
src
attribute, and it makes it harder to understand what you actually want to compare: that the two images selected are of the same thing - Why are you converting integers to strings when you put them into
tempCheckArr
and converting them back when you take them out? Wouldn't it be easier to just put integers into the array?
How I would write it
const IMAGES = ["cat", "cat", "dog", "dog", "horse", "horse", "pig",
"pig", "snake", "snake", "fish", "fish"];
class MemoryGame extends Component
constructor(props)
super(props);
// You can simplify your state a lot
this.state =
cards: shuffleArray(IMAGES.slice()),
selected: , // indexes which have been selected
correct: // indexes which have been guessed correctly
;
// Don't need a componentWillMount
onCardClick(clickedIndex)
const selected, cards, correct = this.state;
if (selected.length === 0) // selecting a first card
this.setState( selected: [clickedIndex] )
else if (selected.length === 1) // they're selecting a second card
if (cards[selected[0]] === cards[clickedIndex])
// It's a match :)
// Add selected cards to `correct` and reset selection
this.setState(
correct: correct.concat([selected[0], clickedIndex]),
selected:
);
else
// It's not a match :(
// Select it for now, and reset selection in a bit
this.setState( selected: [selected[0], clickedIndex] );
setTimeout(() =>
this.setState( selected: )
, 1500);
// Otherwise they already have 2 selected and we don't wanna do anything
render()
const correct, selected, cards = this.state;
return (
<div>
<h1>Memory Game</h1>
<div className="mui-panel wrapper">
cards.map((image, i) => (
<MemoryCard
key=i
image=image
isCorrect=correct.includes(i)
isSelected=selected.includes(i)
onSelect=() => this.onCardClick(i)
/>
))
</div>
</div>
);
// Extracted into it's own component
const MemoryCard = ( image, isSelected, isCorrect, onSelect ) => (
<div
className="modal mui-panel"
onClick=() =>
// You can only select a card that's not already correct and
// isn't currently selected
if (!isCorrect && !isSelected)
onSelect();
>
<img
style=
src="./" + image + ".jpg"
srcSet="./" + image + "_lrg.jpg 1000w"
alt=image
/>
</div>
);
// Probably in a different file
function shuffleArray(array)
for (let i = array.length - 1; i > 0; i--)
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
return array;
export default MemoryGame;
Ok, I had quite a few thoughts on this.
State
Your state seems more complex than it needs to be, and some of it is hiding outside of the state
variable.
I think all you really need to keep track of are:
- What order the images are in
- Which images are currently selected
- Which images have been guessed correctly
I don't really understand what tempCheckArr
is, how it's different from compareImgArr
, or why it's an instance variable.
Extract stuff
I think you have too much stuff crammed into one component.
I think you need to extract pieces of logic that can be self contained.
Prime example: shuffleArray
Why is shuffleArray
declared inside componentWillMount
?
This is creating a new shuffleArray
function every time MemoryGame
is mounted.
I think shuffleArray
should at least be outside of this component, and really should be in a some sort of RandomUtil.js
file.
Card component
I would also extract out a Card component that renders a card.
It should know:
- What image to display
- Whether or not it's selected
- Whether or not it's been guessed correctly
This way you can keep your MemoryGame component about managing the state of the game while the Card component focuses on presentation.
Other Thoughts
- Your
<img>
tag doesn't need akey
prop because it's not the top level thing in an array. - Why is
ImagePieces
declared onthis
. It seems like it should be part of state. - (Also why is the
I
inImagePieces
uppercase? It seems like this should beimagePieces
) - Why are you shuffling ImagePieces in componentWillMount and not just in the constructor?
- It's kinda gross to reach into the DOM to compare the elements
src
attribute, and it makes it harder to understand what you actually want to compare: that the two images selected are of the same thing - Why are you converting integers to strings when you put them into
tempCheckArr
and converting them back when you take them out? Wouldn't it be easier to just put integers into the array?
How I would write it
const IMAGES = ["cat", "cat", "dog", "dog", "horse", "horse", "pig",
"pig", "snake", "snake", "fish", "fish"];
class MemoryGame extends Component
constructor(props)
super(props);
// You can simplify your state a lot
this.state =
cards: shuffleArray(IMAGES.slice()),
selected: , // indexes which have been selected
correct: // indexes which have been guessed correctly
;
// Don't need a componentWillMount
onCardClick(clickedIndex)
const selected, cards, correct = this.state;
if (selected.length === 0) // selecting a first card
this.setState( selected: [clickedIndex] )
else if (selected.length === 1) // they're selecting a second card
if (cards[selected[0]] === cards[clickedIndex])
// It's a match :)
// Add selected cards to `correct` and reset selection
this.setState(
correct: correct.concat([selected[0], clickedIndex]),
selected:
);
else
// It's not a match :(
// Select it for now, and reset selection in a bit
this.setState( selected: [selected[0], clickedIndex] );
setTimeout(() =>
this.setState( selected: )
, 1500);
// Otherwise they already have 2 selected and we don't wanna do anything
render()
const correct, selected, cards = this.state;
return (
<div>
<h1>Memory Game</h1>
<div className="mui-panel wrapper">
cards.map((image, i) => (
<MemoryCard
key=i
image=image
isCorrect=correct.includes(i)
isSelected=selected.includes(i)
onSelect=() => this.onCardClick(i)
/>
))
</div>
</div>
);
// Extracted into it's own component
const MemoryCard = ( image, isSelected, isCorrect, onSelect ) => (
<div
className="modal mui-panel"
onClick=() =>
// You can only select a card that's not already correct and
// isn't currently selected
if (!isCorrect && !isSelected)
onSelect();
>
<img
style=
src="./" + image + ".jpg"
srcSet="./" + image + "_lrg.jpg 1000w"
alt=image
/>
</div>
);
// Probably in a different file
function shuffleArray(array)
for (let i = array.length - 1; i > 0; i--)
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
return array;
export default MemoryGame;
answered Feb 2 at 20:07
Simon Baumgardt-Wellander
1863
1863
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f184488%2fmemory-game-in-react%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password