Home > database >  Why is this conditional rendering not working?
Why is this conditional rendering not working?

Time:01-22

I'm practicing memory game and working on a logic where if two cards are flipped and they are not equal value then flip back to hide the value. Basically,{trackFlip[idx] && cell} is the part in question. I even console.logged the trackFlip object from flipBack function to check to make sure the clicked card value is set to false, and they are, but this conditional rendering still fails. When two unmatched values still display on the screen instead of disappearing. Not sure what's wrong with the logic. https://codesandbox.io/s/frontend-eval-memory-game-ts-8yyfmq?file=/src/App.tsx:0-2438

import "./styles.css";
import React, { useState, useEffect } from "react";

const generateRandomNumbers = (totalNums: number) => {
  let halfNums = totalNums / 2;
  let count = 0;
  let arr = [];
  for (let i = 0; i < halfNums; i  ) {
    arr.push(i);
  }
  arr = [...arr, ...arr];
  let j = arr.length;
  while (--j > 0) {
    let temp = Math.floor(Math.random() * (j   1));
    [arr[temp], arr[j]] = [arr[j], arr[temp]];
  }

  return arr;
};

interface Hash {
  [key: number]: boolean;
}

function createFlipTracker(j: number) {
  let hash: Hash = {};
  for (let j = 0; j < 36; j  ) {
    hash[j] = false;
  }

  return hash;
}

export default function App() {
  const [board, setBoard] = useState(generateRandomNumbers(36));
  const [trackFlip, setTrackFlip] = useState(createFlipTracker(36));
  const [solved, setSolved] = useState<number[]>([]);

  const handleClick = (num: number, idx: number) => {
    let copiedTrackFlip = { ...trackFlip };
    if (copiedTrackFlip[idx]) {
      copiedTrackFlip[idx] = false;
      setTrackFlip(copiedTrackFlip);
    } else {
      copiedTrackFlip[idx] = true;
      setTrackFlip(copiedTrackFlip);
    }
    let flippedCell = Object.keys(copiedTrackFlip).filter(
      (val) => copiedTrackFlip[Number(val)] === true
    );
    console.log(flippedCell);
    function flipBack(x: number, y: number) {
      copiedTrackFlip[x] = false;
      copiedTrackFlip[y] = false;
      console.log(copiedTrackFlip);
      setTrackFlip(copiedTrackFlip);
    }
    if (flippedCell.length === 2) {
      let [x, y] = flippedCell;
      if (board[Number(x)] !== board[Number(y)]) {
        setTimeout(() => {
          flipBack(Number(x), Number(y));
        }, 1000);
      } else {
        setTimeout(() => {
          flipBack(Number(x), Number(y));
          let copiedSolved = [...solved];
          copiedSolved.push(Number(x));
          copiedSolved.push(Number(y));
          setSolved(copiedSolved);
        }, 1000);
      }
    }
  };

  const handleWinner = (idx: number) => {
    if (solved.includes(idx)) {
      return "solvedCell";
    }
  };

  return (
    <div className="board-container">
      {board.map((cell, idx) => {
        return (
          <div
            className={`cell ${handleWinner(idx)}`}
            data-cell={idx}
            onClick={() => handleClick(cell, idx)}
          >
            {trackFlip[idx] && cell}
          </div>
        );
      })}
    </div>
  );
}

CodePudding user response:

Try this:

function flipBack(x: number, y: number) {
      trackFlip[x] = false;
      trackFlip[y] = false;
      console.log(trackFlip);
      setTrackFlip({...trackFlip});
}

Explanation: It looks like you're setting the copiedTrackFlip object inside the function, but since it's a copy of the original trackFlip object and not the actual object, the changes are not being reflected in the component.

Also, you may want to use the spread operator inside the setTrackFlip function to make sure that react knows that this is a new object and should re-render the component.

NB: Not tested but worth a try.

  • Related