简体   繁体   中英

Tree re-rendering in react

I am running this code and every time i click on an object the whole element tree re-renders.Since my handleClick method is inside the renderCard method, shouldn't the element i am clicking be the only one that re-renders. I am thinking it has to do with the individuality of the the renderCard method and since each one is not specific that's why all of them re-render, so should i pass as prop the number of the card i want to re-render?If not what's wrong?

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

class CardNEW extends React.Component{

    render(){
        return(
            <span className={"card rank-" + this.props.rank+" "+this.props.suit+""}>
                        <span className="rank">{this.props.rank}</span>
                        <span className="suit"></span>
                    </span>
            );
    }
    }


class Game extends React.Component{
    constructor(){
        super();
        this.newdeck=this.deckCreator();
        this.handleClick = this.handleClick.bind(this);
    }
    deckCreator(){
        const deckdiamonds=[];
        const deckspades=[];
        const deckclubs=[];
        const deckhearts=[];
      for(let i=0;i<13;i++){
        if(i==0){
            deckspades.push(['a','spades'])
        }else if(i==10){
            deckspades.push(['j','spades'])
        }else if(i==11){
            deckspades.push(['q','spades'])
        }else if(i==12){
            deckspades.push(['k','spades'])
        }else{
        deckspades.push([i+1,'spades'])
        }
      }
      for(let k=0;k<13;k++){
        if(k==0){
            deckdiamonds.push(['a','diams'])
        }else if(k==10){
            deckdiamonds.push(['j','diams'])
        }else if(k==11){
            deckdiamonds.push(['q','diams'])
        }else if (k==12) {
            deckdiamonds.push(['k','diams'])
        }else{
        deckdiamonds.push([k+1,'diams'])
        }   
      }
      for(let l=0;l<13;l++){
        if(l==0){
            deckclubs.push(['a','clubs'])
        }else if(l==10){
            deckclubs.push(['j','clubs'])
        }else if(l==11){
            deckclubs.push(['q','clubs'])
        }else if (l==12) {
            deckclubs.push(['k','clubs'])
        }else{
        deckclubs.push([l+1,'clubs'])
      }
    }   
      for(let m=0;m<13;m++){
        if(m==0){
            deckhearts.push(['a','hearts'])
        }else if(m==10){
            deckhearts.push(['j','hearts'])
        }else if(m==11){
            deckhearts.push(['q','hearts'])
        }else if (m==12) {
            deckhearts.push(['k','hearts'])
        }else{
        deckhearts.push([m+1,'hearts'])
      }
      }
      return deckdiamonds.concat(deckspades,deckclubs,deckhearts);
    }   
    handleClick(i){
            this.setState({rank:1 ,suit:2})
            console.log('yo' + this.state);
    }

    cardDraw(deck){ 
    let cut=Math.floor((Math.random() * deck.length) + 0);
    let card=deck.splice(cut, 1);
    console.log('ya' + this.state);
    return card;
    }

    renderCard(i){  
        const newcard=this.cardDraw(this.newdeck);
                return(
                <button onClick={this.handleClick}>
                    <span className="playingCards simpleCards">
                        <CardNEW rank={newcard[0][0]} suit={newcard[0][1]}/>                    
                    </span>
                </button>); 
    }

    render() {
    return (
      <span>
        <span className="opponent-hand">
          {this.renderCard(1)}
            {console.log('yei')}
          {this.renderCard(2)}          
          {this.renderCard(3)}
          {this.renderCard(4)}
          {this.renderCard(5)}
        </span>
        <div className="my-hand">
          {this.renderCard(6)}
          {this.renderCard(7)}
          {this.renderCard(8)}
          {this.renderCard(9)}
          {this.renderCard(0)}
        </div>
      </span>
    );
  }
}

ReactDOM.render(<Game />, document.getElementById("root"));

Some extra info: The logs are used to identify my problem, disregard them. I know there may be some anti-patterns in there but i started last week with js so i am learning.ALSO VERY IMPORTANT i know that the handleclick method doesn't do anything and it setstates to object Object, this is a problem i will solve later

React's render functionality works like this;

  1. State is changed via setState .
  2. React performs an invisible test re-render of the component whose state was changed on the "virtual dom".
  3. As a result of step 2, react re-renders all sub components on the virtual dom as well. This continues recursively until it finds a non-component element.
  4. For every element re-rendered on the virtual dom, react compares the new result with the previous result.
  5. If the new result does not match the previous result, react re-renders the sub component.

With that in mind, consider how your code feeds into this flow; On the virtual dom render, your code is going to re-run the cardDraw method, which produces a random result. This means that it will always produce a unique outcome, and always be re-rendered.

If you want to prevent this, you need to store the first outcome of cardDraw in a location where you can reference the previous result, and therefore preserve the same render of the sub-components. The proper place to store this outcome is on the state.

I would create an array of size 10 on the state, and populate it with 10 calls to cardDraw . Then reference this.state.cards[index] whenever you need to retrieve a previously drawn card.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM