Memory Game in React

The name of the pictureThe name of the pictureThe name of the pictureClash 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;






share|improve this question



























    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;






    share|improve this question























      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;






      share|improve this question













      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;








      share|improve this question












      share|improve this question




      share|improve this question








      edited Jan 21 at 21:07









      200_success

      123k14143401




      123k14143401









      asked Jan 6 at 22:50









      Franky

      465




      465




















          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 a key prop because it's not the top level thing in an array.

          • Why is ImagePieces declared on this. It seems like it should be part of state.

          • (Also why is the I in ImagePieces uppercase? It seems like this should be imagePieces)

          • 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;





          share|improve this answer





















            Your Answer




            StackExchange.ifUsing("editor", function ()
            return StackExchange.using("mathjaxEditing", function ()
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            );
            );
            , "mathjax-editing");

            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "196"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );








             

            draft saved


            draft discarded


















            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






























            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 a key prop because it's not the top level thing in an array.

            • Why is ImagePieces declared on this. It seems like it should be part of state.

            • (Also why is the I in ImagePieces uppercase? It seems like this should be imagePieces)

            • 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;





            share|improve this answer

























              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 a key prop because it's not the top level thing in an array.

              • Why is ImagePieces declared on this. It seems like it should be part of state.

              • (Also why is the I in ImagePieces uppercase? It seems like this should be imagePieces)

              • 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;





              share|improve this answer























                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 a key prop because it's not the top level thing in an array.

                • Why is ImagePieces declared on this. It seems like it should be part of state.

                • (Also why is the I in ImagePieces uppercase? It seems like this should be imagePieces)

                • 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;





                share|improve this answer













                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 a key prop because it's not the top level thing in an array.

                • Why is ImagePieces declared on this. It seems like it should be part of state.

                • (Also why is the I in ImagePieces uppercase? It seems like this should be imagePieces)

                • 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;






                share|improve this answer













                share|improve this answer



                share|improve this answer











                answered Feb 2 at 20:07









                Simon Baumgardt-Wellander

                1863




                1863






















                     

                    draft saved


                    draft discarded


























                     


                    draft saved


                    draft discarded














                    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













































































                    Popular posts from this blog

                    Greedy Best First Search implementation in Rust

                    Function to Return a JSON Like Objects Using VBA Collections and Arrays

                    C++11 CLH Lock Implementation