1

I'm trying to accomplish two things. One, onClick, I am adding values to a state property, cardPairs. I made a copy of the state object and used concat to add a value. It takes me three clicks to create a match. The first time I click, I get the empty array, then on two subsequent correct clicks, I'll have a match. Using push doesn't work on my copy, I get a "could not consume" error and when trying push, I get "object is not extensible". How can I match on two clicks? The second issue is removing the matched items from the UI.

class CardCollectionTwo extends Component {
  constructor(props) {
    super(props);
    this.state = {
      hidden: false,
      cardPairs: []
    };
    this.compareCards = this.compareCards.bind(this);
  }

  compareCards(e) {
    const pairs = Object.freeze(this.state.cardPairs)
    console.log(pairs)
    this.setState({ cardPairs: pairs.concat(e.target.value) });
    console.log(this.state);
    if(pairs[0] === pairs[1] && pairs.length!== 0){
      console.log('MATCH')
    }else if(pairs.length === 2){
        this.setState(prevState => ({ cardPairs: [] }))
   }
 }
 render() {
    let cards = this.props.cardsEasy["cards"].map((item, index) => {
      return (
    <button
      style={btn}
      value={item}
      id={item}
      onClick={this.compareCards}
      key={item + index}
    >
      {item}
    </button>
  );
});
return <CardTwo cards={cards} />;
 }
   }

export default CardCollectionTwo;

1 Answer 1

2

Push and Object.freeze()

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze

Object.freeze() prevents elements from being added to the array (in your case, via push). Object.freeze() prevents additions, removals, and changes to whatever it is applied to (array pushes/modifications, objects, etc). To properly copy, you can use the Array.slice() (this.state.cardPairs.slice()), which returns a shallow copy of the source.

concat does not modify the array, while push does. concat() returns a new array that is the combination of 2 arrays, while push() adds an element to the current array. This is why push() does not work on a frozen object, while concat does.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice

Answering the matching question:

if (pairs[0] === pairs[1] && pairs.length!== 0){
  console.log('MATCH')
} else if(pairs.length === 2){
    this.setState(prevState => ({ cardPairs: [] }))
}

There is an error in your logic. Basically, you concatenate the new pair value and commit it to your state (via this.setState({ cardPairs: pairs.concat(e.target.value })). However, this if conditional is relying on that e.target.value, and so the pairs variable is outdated.

Also, it seems code-wise you are strictly only comparing the first two elements of the array, which leads to the infinite mismatch problem.

Solution

We can take a different approach: Firstly, whenever a new, unique value is clicked, add it to the array. However, if we come upon a value that is already in the array, then that means we have a match. We can then filter out the element (there is probably a remove function that'd work well too). That means that our pairs will always only contain unique values, and will drop unique values whenever there are matches.

const pairs = this.state.cardPairs.slice();
if (pairs.includes(e.target.value)) {
  console.log("Match");
  this.setState({ cardPairs: pairs.filter(el => el != e.target.value )})
} else {
  // Otherwise, add more elements to the list.
  this.setState({ cardPairs: pairs.concat(e.target.value) });
}

User clicks 1: [1]

User clicks 1 again: []

User clicks 0, 1: [0,1]

User clicks 1: [0]

Sandbox: https://codesandbox.io/s/4jmjp3l94x

Sign up to request clarification or add additional context in comments.

6 Comments

I did that already, and it still takes three clicks for the match const pairs = this.state.cardPairs.slice()
Hi, I updated the answer just now. In your if conditional, you are using the old array that does not have the new pair concatenated to it.
I did what you said, still three clicks... codesandbox
Sorry, please reexamine the code. I sent you buggy code, but now it should work. codesandbox.io/s/2xrz1j8mmn Here is a live example too. Basically, I provided you the wrong code for using the this.setState callback. To use the new state, you just have to recall this.state.cardPairs. However, I think I am not answering the question correctly (for removing the matched elements).
You want to match any duplicates in the array right? Like if the user clicks 0->0, match. But if the user clicks 0->1->0, remove both 0's? If so, we will have to change the answer to not rely on simply the first 2 elements of the array..
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.