Berke Özbek
Berke Özbek

Reputation: 59

How do I solve the problem of copying data in reference type?

I'm making a simple card game. I want to update the data in state, but the data I keep in data is being updated, how can I solve this problem? I have the right to click 2 times in the game and when similar cards are matched, they disappear. I can't refresh when all cards are matched

I can match the same cards, but I cannot restart when I want to restore them, and when I examine them, I cannot update the data in the state. So in short my reset function doesn't work

my AllCards component

import * as React from 'react'
import { Card } from './components/Card'
import { cardState, ICard } from './Types'
import {data} from './data'


interface IState {
    cards: ICard[]
}

class AllCards extends React.Component<{}, IState>{
    selectedCardIds: number [] = [];
    selectedCards: ICard[] = []
    state: IState= {
        cards: [...data]
    }
    cardClickHandler = (card: ICard) =>{
        const {cards} =this.state
        if (this.selectedCardIds.length< 2){
            this.selectedCardIds.push(card.id)
            this.selectedCards.push(card)
            this.setState({
                ...this.state,
                cards: cards.map(c => c.id === card.id ? card: c) 
            }, this.checkMarch)
        }         
        //console.log({card});

    }
    checkMarch = () =>{
        if (this.selectedCardIds.length === 2  ){
            setTimeout(() => {
                let newCards: ICard[] = []
            const {cards} =this.state
            let nextState: cardState = "unmatched"

            if(this.selectedCards[0].content === this.selectedCards[1].content){                 
                    nextState = "matched" 
            }
            newCards = cards.map(c=>{
                if(this.selectedCardIds.includes(c.id)){
                    c.state = nextState
                }
                return c
            })
            
            
                this.selectedCardIds= []
            this.selectedCards= []
            this.setState({
                ...this.state,
                cards: newCards
            })
            }, 500);  
            }

    }
    
     reset = () =>{
        console.log("reset");
    this.selectedCardIds = []
    this.selectedCards = []
    this.setState({
        ...this.state,
        cards: data
    })
}
render() {
    const cardList = this.state.cards.map(c => (<Card key={c.id} card={c} clickHandler={this.cardClickHandler}/>))
    return (
        <div className='container p-3 bg-dark-gray'>
            <div className="row row-cols-1 row-cols-md-3 g-4" style={{columnCount:2}}>
                {cardList}
            </div>
            <hr />
            <button onClick={this.reset} className='btn btn-primary'> retyrn</button>

        </div>
    )
}
}
     export {AllCards}

Upvotes: 0

Views: 40

Answers (2)

Benjamin U.
Benjamin U.

Reputation: 638

If the data you're trying to update is one level deep (i.e., doesn't contain any nested objects or arrays), Talha's answer will work. However, if your data is more than one level deep, you run the risk of accidentally mutating the child object. For example,

const test1 = {
  a: 1,
  b: 2,
  c: {
    d: 4,
  },
};

// Direct assignment
const test2 = test1;
test2.a = 5;
console.log(test1.a, test2.a); // 5, 5

// Assigning via spreading (shallow cloning)
const test3 = { ...test1 };
test3.b = 7;
console.log(test1.b, test3.b); // 2, 7

test3.c.d = 9;
console.log(test1.c.d, test3.c.d); // 9, 9

This answer describes how to deeply clone an object, which will resolve the above issue.

If you want a quick and dirty way to deep-clone an object, you can use JSON.parse and JSON.stringify like so:

const test1 = {
  a: 1,
  b: 2,
  c: {
    d: 4,
  },
}

// Assignment via stringifying/de-stringifying (deep cloning)
const test2 = JSON.parse(JSON.stringify(test1));
test2.c.d = 9;
console.log(test1.c.d, test2.c.d); // 4, 9

Upvotes: 1

Talha Akca
Talha Akca

Reputation: 402

if you want to get rid of the reference just spread it like

data = {..state.data}  // if its object,
data = [...state.data] // if its array

therefore if your state.data gets updated, data will not going to get affected by the changes

Upvotes: 1

Related Questions