Reputation: 758
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;
Upvotes: 1
Views: 4284
Reputation: 591
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.
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
Upvotes: 2